Skip to content

Commit

Permalink
Merge pull request #14 from SpeedCurve-Metrics/feature/rum-page-groups
Browse files Browse the repository at this point in the history
Handle pagegroups in lux.js
  • Loading branch information
elenakondrateva authored Sep 14, 2022
2 parents 16c5dc2 + e88e132 commit 827c8b6
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 40 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ To publish a new version to [private GitHub Packages](https://github.com/orgs/Sp
```
export NPM_AUTH_TOKEN="%token%"
```
3. Run `npm publish` (use username `speedcurve-bot` and token from previous step if it requies login)
3. Login to Github Packages with your Github user's credentials (or `speedcurve-bot`):
```
npm login --scope=@speedcurve-metrics --registry=https://npm.pkg.github.com
```
4. Run `npm publish`

Read more: [Working with the npm registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry)
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@speedcurve-metrics/lux.js",
"version": "1.0.4",
"version": "3.0.2",
"scripts": {
"build": "npm run rollup",
"rollup": "rollup -c rollup.config.js",
Expand All @@ -11,6 +11,7 @@
"lint-fix": "npm run lint -- --fix",
"test": "npm run type-check && npm run lint && npm run jest",
"test-unit": "npm run jest /tests/unit --watchAll",
"test-integration": "npm run jest /tests/integration --watchAll",
"watch": "npm run rollup -- --watch"
},
"devDependencies": {
Expand Down
5 changes: 5 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export interface ConfigObject {
samplerate: number;
sendBeaconOnPageHidden: boolean;
trackErrors: boolean;
pagegroups?: PageGroups;
}
interface PageGroups {
[key: string]: string[];
}

export type UserConfig = Partial<ConfigObject>;
Expand All @@ -35,6 +39,7 @@ export function fromObject(obj: UserConfig): ConfigObject {
samplerate: getProperty(obj, "samplerate", 100),
sendBeaconOnPageHidden: getProperty(obj, "sendBeaconOnPageHidden", autoMode),
trackErrors: getProperty(obj, "trackErrors", true),
pagegroups: getProperty(obj, "pagegroups", undefined),
};
}

Expand Down
1 change: 1 addition & 0 deletions src/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const Flags = {
PageLabelFromDocumentTitle: 1 << 6,
PageLabelFromLabelProp: 1 << 7,
PageLabelFromGlobalVariable: 1 << 8,
PageLabelFromPagegroup: 1 << 9,
};

export function addFlag(flags: number, flag: number): number {
Expand Down
25 changes: 24 additions & 1 deletion src/lux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
PerfTimingKey,
} from "./performance";
import now from "./now";
import Matching from "./matching";

declare const __ENABLE_POLYFILLS: boolean;

Expand Down Expand Up @@ -1753,7 +1754,29 @@ LUX = (function () {
gFlags = addFlag(gFlags, Flags.PageLabelFromLabelProp);

return LUX.label;
} else if (typeof LUX.jspagelabel !== "undefined") {
} else if (typeof LUX.pagegroups !== "undefined") {
const pagegroups = LUX.pagegroups;
const url = `${document.location.hostname}${document.location.pathname}`;
let label = "";
for (const pagegroup in pagegroups) {
const rules = pagegroups[pagegroup];
if (Array.isArray(rules)) {
rules.every((rule: string) => {
if (Matching.isMatching(rule, url)) {
label = pagegroup;
return false; // stop when first match is found
}
return true;
});
}
// exits loop when first match is found
if (label.length) {
gFlags = addFlag(gFlags, Flags.PageLabelFromPagegroup);
return label;
}
}
}
if (typeof LUX.jspagelabel !== "undefined") {
const evaluateJsPageLabel = Function(`"use strict"; return ${LUX.jspagelabel}`);

try {
Expand Down
18 changes: 0 additions & 18 deletions src/matching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,4 @@ export default class Matching {
// we don't escape * because it's our own special symbol!
return string.replace(/[-/\\^$+?.()|[\]{}]/g, "\\$&");
}

/**
* Prepares URL for matching: removes protocol and query string
* E.g. https://speedcurve.com/path/name/?ok becomes speedcurve.com/path/name/
* Used in UI
*
* @param url
*/
static cleanUrl(url: string): string | null {
try {
const { hostname, pathname } = new URL(url);
return `${hostname}${pathname}`;
} catch (e) {
console.debug(`Invalid URL ${url}`);
}

return null;
}
}
55 changes: 55 additions & 0 deletions tests/integration/lux-page-label.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe("LUX page labels", () => {
expect(hasFlag(beacon, Flags.PageLabelFromDocumentTitle)).toBe(true);
expect(hasFlag(beacon, Flags.PageLabelFromLabelProp)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromGlobalVariable)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromPagegroup)).toBe(false);
});

test("using a custom label", async () => {
Expand All @@ -23,6 +24,7 @@ describe("LUX page labels", () => {
expect(hasFlag(beacon, Flags.PageLabelFromLabelProp)).toBe(true);
expect(hasFlag(beacon, Flags.PageLabelFromDocumentTitle)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromGlobalVariable)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromPagegroup)).toBe(false);
});

test("custom label is null", async () => {
Expand All @@ -34,6 +36,35 @@ describe("LUX page labels", () => {
expect(hasFlag(beacon, Flags.PageLabelFromDocumentTitle)).toBe(true);
expect(hasFlag(beacon, Flags.PageLabelFromLabelProp)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromGlobalVariable)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromPagegroup)).toBe(false);
});

test("using a pagegroup label", async () => {
await navigateTo(
"/default.html?injectScript=LUX.label=null;LUX.pagegroups={'Pagegroup':['localhost/default.html']};"
);
const luxRequests = requestInterceptor.createRequestMatcher("/beacon/");
const beacon = luxRequests.getUrl(0);

expect(beacon.searchParams.get("l")).toEqual("Pagegroup");
expect(hasFlag(beacon, Flags.PageLabelFromPagegroup)).toBe(true);
expect(hasFlag(beacon, Flags.PageLabelFromLabelProp)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromDocumentTitle)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromGlobalVariable)).toBe(false);
});

test("LUX.label takes priority over pagegroup label", async () => {
await navigateTo(
"/default.html?injectScript=LUX.pagegroups={'Pagegroup':['localhost/default.html']};LUX.label='custom label';"
);
const luxRequests = requestInterceptor.createRequestMatcher("/beacon/");
const beacon = luxRequests.getUrl(0);

expect(beacon.searchParams.get("l")).toEqual("custom label");
expect(hasFlag(beacon, Flags.PageLabelFromPagegroup)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromLabelProp)).toBe(true);
expect(hasFlag(beacon, Flags.PageLabelFromDocumentTitle)).toBe(false);
expect(hasFlag(beacon, Flags.PageLabelFromGlobalVariable)).toBe(false);
});
});

Expand Down Expand Up @@ -150,6 +181,30 @@ describe("LUX page labels", () => {
expect(luxRequests.getUrl(1).searchParams.get("l")).toEqual("JS Label");
});

test("LUX.pagegroups takes priority over JS page label", async () => {
await page.evaluate("LUX.init()");
await page.evaluate("LUX.pagegroups = {'Pagegroup':['localhost/default.html']}");
await page.evaluate("LUX.send()");

expect(luxRequests.getUrl(0).searchParams.get("l")).toEqual("Pagegroup");

await page.evaluate("LUX.init()");
await page.evaluate("delete LUX.pagegroups");
await page.evaluate("window.config.page[0].name = 'JS Label'");
await page.evaluate("LUX.send()");

expect(luxRequests.getUrl(1).searchParams.get("l")).toEqual("JS Label");
});

test("falls back to JS variable when pagegroup doesn't match", async () => {
await page.evaluate("LUX.init()");
await page.evaluate("window.config.page[0].name = 'JS Label'");
await page.evaluate("LUX.pagegroups = {'Pagegroup':['/not-this-page/*']}");
await page.evaluate("LUX.send()");

expect(luxRequests.getUrl(0).searchParams.get("l")).toEqual("JS Label");
});

test("falls back to document title when JS variable doesn't eval", async () => {
await page.evaluate("LUX.init()");
await page.evaluate("window.config = {}");
Expand Down
19 changes: 0 additions & 19 deletions tests/unit/matching.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,3 @@ describe("Test subdomain matching", () => {
expect(Matching.isMatching("*.speedcurve.com/*/bar", "speedcurve.com/foo/baz/bar")).toBe(false);
});
});

describe("Test cleanUrl method", () => {
test("cleanUrl returns null if URL is invalid", () => {
expect(Matching.cleanUrl("speedcurve.com")).toBe(null);
expect(Matching.cleanUrl("random string")).toBe(null);
expect(Matching.cleanUrl("https://invalid domain")).toBe(null);
});

test("cleanUrl returns modyfied URL", () => {
expect(Matching.cleanUrl("https://speedcurve.com/pathname/")).toBe("speedcurve.com/pathname/");
expect(Matching.cleanUrl("https://speedcurve.com/pathname/?ok")).toBe(
"speedcurve.com/pathname/"
);
expect(Matching.cleanUrl("https://www.speedcurve.com/path/name/?ok")).toBe(
"www.speedcurve.com/path/name/"
);
expect(Matching.cleanUrl("http://app.speedcurve.com/")).toBe("app.speedcurve.com/");
});
});

0 comments on commit 827c8b6

Please sign in to comment.