Skip to content

Commit

Permalink
feat:(service-worker): added new service-worker compatible SDK export…
Browse files Browse the repository at this point in the history
… with samples

* feat:(service-worker): new service worker compatible SDK added

* feat:(service-worker): add build configuration for service worker

* feat:(service-worker): updated gitignore file with service worker build artifacts

* feat:(service-worker): added unit test for service worker

* docs(chrome-extension): added documentation on usage for chrome extensions
  • Loading branch information
bardisg authored Oct 17, 2022
1 parent f29b99d commit aad7095
Show file tree
Hide file tree
Showing 43 changed files with 42,414 additions and 6,848 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ publish.sh
dist/*
!dist/rudder-sdk-js/*
dist/rudder-sdk-js/index.js
dist/rudder-sdk-js/service-worker/
coverage/**
__tests__/prodsdk.js
.eslintcache
.idea
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The JavaScript SDK lets you track customer event data from your website and send
- [**The `ready` API**](https://github.com/rudderlabs/rudder-sdk-js/blob/master/README.md#the-ready-api)
- [**Self-hosted control plane**](https://github.com/rudderlabs/rudder-sdk-js/blob/master/README.md#self-hosted-control-plane)
- [**Adding your own integrations**](https://github.com/rudderlabs/rudder-sdk-js/blob/master/README.md#adding-your-own-integrations)
- [**Usage in Chrome Extensions**](https://github.com/rudderlabs/rudder-sdk-js/blob/master/README.md#usage-in-chrome-extensions)

| **IMPORTANT**: We have deprecated the Autotrack feature for the RudderStack JavaScript SDK and it will soon be removed. If you still wish to use it for your project, refer to [**this repository**](https://github.com/rudderlabs/rudder-sdk-js-autotrack#autotrack). |
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down Expand Up @@ -297,6 +298,13 @@ You can start adding integrations of your choice for sending the data through th
- For adding or removing integrations, modify the imports in `index.js` under the `integrations` folder.

### Usage in Chrome Extensions

RudderStack JS SDK can be used in Chrome Extensions with manifest v3, both as a content script or as a background script
service worker.

For examples and specific details look into [Chrome Extensions Usage](https://github.com/rudderlabs/rudder-sdk-js/blob/master/tests/chrome-extension/USAGE.md)

## Contribute

We would love to see you contribute to this project. Get more information on how to contribute [**here**](./CONTRIBUTING.md).
Expand Down
79 changes: 79 additions & 0 deletions __tests__/service-worker/__mocks__/fixtures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const identifyRequestPayload = {
userId: '123456',
traits: {
name: 'Name Username',
email: 'name@website.com',
plan: 'Free',
friends: 21,
},
};

const trackRequestPayload = {
userId: '123456',
event: 'Item Viewed',
properties: {
revenue: 19.95,
shippingMethod: 'Premium',
},
};

const pageRequestPayload = {
userId: '12345',
category: 'Food',
name: 'Pizza',
properties: {
url: 'https://dominos.com',
title: 'Pizza',
referrer: 'https://google.com',
},
};

const screenRequestPayload = {
userId: '12345',
category: 'Food',
name: 'Pizza',
properties: {
screenSize: 10,
title: 'Pizza',
referrer: 'https://google.com',
},
};

const groupRequestPayload = {
userId: '12345',
groupId: '1',
traits: {
name: 'Company',
description: 'Google',
},
};

const aliasRequestPayload = {
previousId: 'old_id',
userId: 'new_id',
};

const dummyWriteKey = 'dummyWriteKey';

const dummyDataplaneHost = 'https://dummy.dataplane.host.com';

const dummyInitOptions = {
timeout: false,
flushAt: 1,
flushInterval: 200000,
maxInternalQueueSize: 1,
logLevel: 'off',
enable: true,
};

export {
identifyRequestPayload,
trackRequestPayload,
pageRequestPayload,
screenRequestPayload,
groupRequestPayload,
aliasRequestPayload,
dummyWriteKey,
dummyInitOptions,
dummyDataplaneHost,
};
12 changes: 12 additions & 0 deletions __tests__/service-worker/__mocks__/msw.server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { setupServer } from 'msw/node';
import { dummyDataplaneHost } from './fixtures';

const server = setupServer({
url: `${dummyDataplaneHost}/v1/batch`,
response: () => null,
status: 200,
method: 'post',
responseHeaders: { Environment: 'local' },
});

export { server };
109 changes: 109 additions & 0 deletions __tests__/service-worker/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { advanceTo } from 'jest-date-mock';
import { Analytics } from '../../service-worker';
import { server } from './__mocks__/msw.server';
import {
aliasRequestPayload,
dummyDataplaneHost,
dummyInitOptions,
dummyWriteKey,
groupRequestPayload,
identifyRequestPayload,
pageRequestPayload,
screenRequestPayload,
trackRequestPayload,
} from './__mocks__/fixtures';

jest.mock('uuid', () => ({ v4: () => '123456789' }));

describe('JS SDK Service Worker', () => {
let rudderAnalyticsClient = null;
let requestBody;

beforeAll(() => {
advanceTo(new Date(2022, 1, 21, 0, 0, 0));
server.listen();
});

beforeEach(() => {
rudderAnalyticsClient = new Analytics(dummyWriteKey, dummyDataplaneHost, dummyInitOptions);
server.events.on('request:start', (req) => {
requestBody = req.body;
});
});

afterEach(() => {
rudderAnalyticsClient = null;
server.resetHandlers();
server.events.removeAllListeners();
requestBody = null;
});

afterAll(() => {
server.close();
});

it('Should initialise with correct values', () => {
expect(rudderAnalyticsClient.writeKey).toBe(dummyWriteKey);
expect(rudderAnalyticsClient.host).toBe(dummyDataplaneHost);
expect(rudderAnalyticsClient.timeout).toBe(dummyInitOptions.timeout);
expect(rudderAnalyticsClient.flushAt).toBe(dummyInitOptions.flushAt);
expect(rudderAnalyticsClient.flushInterval).toBe(dummyInitOptions.flushInterval);
expect(rudderAnalyticsClient.maxInternalQueueSize).toBe(dummyInitOptions.maxInternalQueueSize);
expect(rudderAnalyticsClient.logLevel).toBe(dummyInitOptions.logLevel);
expect(rudderAnalyticsClient.enable).toBe(dummyInitOptions.enable);
});

it('Should record identify', async () => {
rudderAnalyticsClient.identify(identifyRequestPayload);
rudderAnalyticsClient.flush();

await new Promise((r) => setTimeout(r, 1));

expect(requestBody.batch[0]).toEqual(expect.objectContaining(identifyRequestPayload));
});

it('Should record track', async () => {
rudderAnalyticsClient.track(trackRequestPayload);
rudderAnalyticsClient.flush();

await new Promise((r) => setTimeout(r, 1));

expect(requestBody.batch[0]).toEqual(expect.objectContaining(trackRequestPayload));
});

it('Should record page', async () => {
rudderAnalyticsClient.page(pageRequestPayload);
rudderAnalyticsClient.flush();

await new Promise((r) => setTimeout(r, 1));

expect(requestBody.batch[0]).toEqual(expect.objectContaining(pageRequestPayload));
});

it('Should record screen', async () => {
rudderAnalyticsClient.screen(screenRequestPayload);
rudderAnalyticsClient.flush();

await new Promise((r) => setTimeout(r, 1));

expect(requestBody.batch[0]).toEqual(expect.objectContaining(screenRequestPayload));
});

it('Should record group', async () => {
rudderAnalyticsClient.group(groupRequestPayload);
rudderAnalyticsClient.flush();

await new Promise((r) => setTimeout(r, 1));

expect(requestBody.batch[0]).toEqual(expect.objectContaining(groupRequestPayload));
});

it('Should record alias', async () => {
rudderAnalyticsClient.alias(aliasRequestPayload);
rudderAnalyticsClient.flush();

await new Promise((r) => setTimeout(r, 1));

expect(requestBody.batch[0]).toEqual(expect.objectContaining(aliasRequestPayload));
});
});
6 changes: 6 additions & 0 deletions dist/rudder-sdk-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
"version": "2.16.0",
"description": "RudderStack Javascript SDK",
"main": "index.js",
"module": "index.es.js",
"exports": {
".": {
"service-worker": "./service-worker/index.es.js"
}
},
"types": "index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand Down
19 changes: 14 additions & 5 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// https://jestjs.io/docs/en/configuration.html

module.exports = {
prettierPath: 'prettier',
// All imported modules in your tests should be mocked automatically
// automock: false,

Expand All @@ -24,7 +25,14 @@ module.exports = {
coverageDirectory: 'coverage',

// An array of regexp pattern strings used to skip coverage collection
coveragePathIgnorePatterns: ['/node_modules/', '/dist/', '/tests/', '/scripts/', '__tests__'],
coveragePathIgnorePatterns: [
'/node_modules/',
'/dist/',
'/tests/',
'/scripts/',
'__tests__',
'__mocks__',
],

// A list of reporter names that Jest uses when writing coverage reports
coverageReporters: ['json', 'text', 'lcov', 'clover'],
Expand Down Expand Up @@ -152,12 +160,12 @@ module.exports = {
// timers: "real",

// A map from regular expressions to paths to transformers
// transform: undefined,
transform: {
'^.+\\.(js|)?$': 'esbuild-jest',
},

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/"
// ],
transformIgnorePatterns: ['<rootDir>/.github/', '<rootDir>/.husky/', '<rootDir>/dist/'],

// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
Expand All @@ -170,4 +178,5 @@ module.exports = {

// Whether to use watchman for file crawling
// watchman: true,
setupFiles: ['jest-date-mock', '<rootDir>/jest/jest.polyfills.js'],
};
1 change: 1 addition & 0 deletions jest/jest.polyfills.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('isomorphic-fetch');
Loading

0 comments on commit aad7095

Please sign in to comment.