Skip to content

Commit

Permalink
add testing for recommendations and track activity. add error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
spacewoox committed Nov 28, 2017
1 parent d8671e2 commit 1a11c79
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 64 deletions.
1 change: 1 addition & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export default {
'HTTP_PROTOCOL': (document.location.protocol == 'https:' ? 'https://' : 'http://'),
'API_URL': 'api.early-birds.fr'
}
31 changes: 11 additions & 20 deletions src/eb.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import {

import { checkActivitiesInputs } from './modules/trackActivityCheck'

const HTTP_PROTOCOL =
(document.location.protocol == 'https:' ? 'https://' : 'http://');

class Eb {
constructor(trackerKey) {
this.defaultProfile = {
Expand Down Expand Up @@ -59,17 +56,15 @@ class Eb {
this.profile = profile
return response;
})
.catch(console.log)
}
return new Promise(r => r(this.defaultProfile));
}

identifyRequest(profile) {
const url = `\
${HTTP_PROTOCOL}\
${Config.HTTP_PROTOCOL}\
${Config.API_URL}\
/tracker/${this.trackerKey}/identify`;
console.log(url)
return fetch(url, {
method: 'POST',
headers: {
Expand All @@ -82,43 +77,40 @@ ${Config.API_URL}\
}

getRecommendations(widgetId) {
if (!widgetId) return false
if (!this.profile) {
return new Promise((r, j) => j('no profile'));
return new Promise((r, j) => j('Earlybirds error: Not identified'));
}
const url = `\
${HTTP_PROTOCOL}\
${Config.HTTP_PROTOCOL}\
${Config.API_URL}\
/widget/${widgetId}\
/recommendations/${this.profile.id}`
return fetch(url)
.then(x => x.json())
.catch(err => {
console.log(err)
return err
throw err
})
}

trackActivity(activities) {

const checkActivityInputsErr = checkActivitiesInputs(activities)
if (checkActivityInputsErr !== true) {
console.log(checkActivityInputsErr)
return false
}

const hash = Encode(JSON.stringify(activities))
console.log(hash)
if (hash === Cookies.getCookie('eb-lastactivity-hash')) {
console.log('this activity has already been tracked')
console.log('Earlybirds : can\'t track the same activity twice')
return false
}

const url = `
${HTTP_PROTOCOL}\
const url = `\
${Config.HTTP_PROTOCOL}\
${Config.API_URL}\
/tracker/${this.trackerKey}\
/activity`
console.log(url)
return fetch(url, {
method: 'post',
body: JSON.stringify({
Expand All @@ -127,13 +119,12 @@ ${Config.API_URL}\
})
.then(x => x.json())
.then(response => {
console.log(response)
Cookies.setCookie('eb-lastactivity-hash', hash)
return response
})
.catch(err => {
console.log(' catch here')
console.log(err)
return err
console.log('Earlybirds error : trackActivity', err)
throw err
})
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/utils/Cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ Cookies.retrieveCookie = function(name) {
}
Cookies.getCookie = function(name) {
const retrievedCookie = this.retrieveCookie(name)
let data = null;
try {
data = JSON.parse(retrievedCookie);
return JSON.parse(retrievedCookie);
} catch (e) {
return retrievedCookie || null;
}
return data;
}
Cookies.setCookie = function(name, value, days) {
let expires = '';
Expand Down
48 changes: 24 additions & 24 deletions src/utils/Utils.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
export const isEqual = (obj1, obj2) => {
for (var i in obj1) {
if (obj1.hasOwnProperty(i)) {
if (!obj2.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
for (var i in obj1) {
if (obj1.hasOwnProperty(i)) {
if (!obj2.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
for (var i in obj2) {
if (obj2.hasOwnProperty(i)) {
if (!obj1.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
}
for (var i in obj2) {
if (obj2.hasOwnProperty(i)) {
if (!obj1.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
return true;
}
return true;
}

export const Encode = object => {
const str = JSON.stringify(object);
let hash = 0;
let i;
let chr;
let len;
if (str.length === 0) return hash;
for (i = 0, len = str.length; i < len; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
return hash;
}
const str = JSON.stringify(object);
let hash = 0;
let i;
let chr;
let len;
if (str.length === 0) return hash;
for (i = 0, len = str.length; i < len; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
return hash;
}
4 changes: 3 additions & 1 deletion src/utils/singleton.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ const makeSingleton = obj => {
let instance = null
return class {
getInstance(params) {
return instance || (instance = new obj(params), instance)
if (!instance)
instance = new obj(params)
return instance
}
reset() {
instance = null
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/cookies.integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ describe('Cookies', () => {
})
it('should store a cookie and retrieve it by its name', () => {
Cookies.setCookie('foo', 'bar')
expect(Cookies.getCookie('foo')).toEqual('bar')
const res = Cookies.getCookie('foo')
expect(res).toEqual('bar')
})
it('should take into account the cookie duration', () => {

Expand Down
139 changes: 124 additions & 15 deletions tests/integration/eb.integration.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Eb from '../../src/eb'
import Cookies from '../../src/utils/Cookies'
import Config from '../../config'
import { Encode } from '../../src/utils/Utils'
import {
shouldInitiateIdentifyRequest } from '../../src/modules/profileValidationCheck'
Expand All @@ -8,6 +9,9 @@ const jasmineDefaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL

beforeEach(() => {

// mute console.log when tests are running.
console.log = () => {}

// avoid using the same instance of Eb for each test
new Eb().reset()

Expand All @@ -19,11 +23,16 @@ beforeEach(() => {
hash: 'fakeHash',
lastIdentify: 10
}

global.DEFAULT_PROFILE = {
hash: null,
lastIdentify: null,
}

// mock http protocol
Config.HTTP_PROTOCOL = 'fakeHttpProtocol/'
Config.API_URL = 'fakeApiUrl'

// fetch should resolve to an empty string by default.
// mock response can be overriden in the test
global.fetch = require('jest-fetch-mock')
Expand Down Expand Up @@ -82,7 +91,7 @@ describe('Earlybirds class', () => {

describe('retrieveEbProfile', () => {

it('should implement a retrieveEbProfile', () => {
it('should implement a retrieveEbProfile method', () => {
expect.assertions(1)

const eb = new Eb().getInstance()
Expand Down Expand Up @@ -308,22 +317,37 @@ describe('Earlybirds class', () => {
expect(eb.trackActivity(fakeInputs)).toEqual(false);
})

it('should make a http request if inputs are ok (happy path)', () => {
expect.assertions(1)
const eb = new Eb().getInstance()
it('should make a http request if inputs are ok then set the eb-lastactivity-hash cookie (happy path)', done => {
expect.assertions(2)
const eb = new Eb().getInstance('fakeTrackerKey')
const fakeInputs = [
{
profile: 'FAKE_PROFILE',
originalId: 'FAKE_ID',
verb: 'FAKE_VERB'
}
]
eb.trackActivity(fakeInputs)
expect(fetch).toBeCalled()
const hash = Encode(JSON.stringify(fakeInputs))
eb
.trackActivity(fakeInputs)
.then(() => {
expect(Cookies.setCookie).toBeCalledWith('eb-lastactivity-hash', hash)
done()
})
const url = `${Config.HTTP_PROTOCOL}${Config.API_URL}/tracker/fakeTrackerKey/activity`
expect(fetch).toBeCalledWith(
url,
{
method: 'post',
body: JSON.stringify({
activity: fakeInputs
})
}
)
})

it('should not make an http request if eb-lastactivity-hash cookie is not new', () => {
// expect.assertions(1)
expect.assertions(1)
const fakeInputs = [
{
profile: 'FAKE_PROFILE',
Expand All @@ -339,7 +363,37 @@ describe('Earlybirds class', () => {
expect(fetch).not.toBeCalled()
})

it('should return an object with activities property', done => {
expect.assertions(1)
const fakeResponse = {}
fakeResponse.json = () => (
new Promise(r =>
r({
activities: [],
})
)
)
const fakeInputs = [
{
profile: 'FAKE_PROFILE',
originalId: 'FAKE_ID',
verb: 'FAKE_VERB'
}
]
fetch = jest.fn(() => (
new Promise(r => r(fakeResponse))
))
const eb = new Eb().getInstance()
eb
.trackActivity(fakeInputs)
.then(response => {
expect(response.activities).toBeDefined()
done()
})
})

it('should catch errors', () => {
expect.assertions(1)
const fakeInputs = [
{
profile: 'FAKE_PROFILE',
Expand All @@ -351,17 +405,72 @@ describe('Earlybirds class', () => {
return new Promise((resolve, reject) => reject('FAKE_ERROR'))
})
const eb = new Eb().getInstance()
const res = eb.trackActivity(fakeInputs)
console.log(res)
res.catch(err => {
console.log('catch err')
console.log(err)
})
/*
eb
.trackActivity(fakeInputs)
.catch(err => {
expect(err).toBe('FAKE_ERROR')
})
*/
})
})

describe('Recommendations', () => {
it('should return a promise that reject with the\
value "Earlybirds error: Not identified" if not identified yet', () => {
const eb = new Eb().getInstance()
eb
.getRecommendations('fakeWidgetId')
.catch(err => {
expect(err).toBe('Earlybirds error: Not identified')
})
})
it('should be falsy if no widgetId is provided', () => {
const eb = new Eb().getInstance()
const res = eb.getRecommendations()
expect(res).toBe(false)
})
it('should make a http call (happy path)', () => {
const eb = new Eb().getInstance('fakeTrackerKey')
eb.profile = {}
const res = eb.getRecommendations('fakeWidgetId')
expect(fetch).toBeCalled()
})
it('should return an object with recommendations and widget', done => {
expect.assertions(2)
const fakeResponse = {}
fakeResponse.json = () => (
new Promise(r =>
r({
recommendations: {},
widget: {}
})
)
)
fetch = jest.fn(() => (
new Promise(r => r(fakeResponse))
))
const eb = new Eb().getInstance()
eb.profile = {}
eb
.getRecommendations('fakeWidgetId')
.then(response => {
expect(response.recommendations).toBeDefined()
expect(response.widget).toBeDefined()
done()
})
})
it('should catch errors', () => {
expect.assertions(1)
fetch = jest.fn(() => {
return new Promise((resolve, reject) => reject('FAKE_ERROR_RECOS'))
})
const eb = new Eb().getInstance()
eb.profile = {}
eb
.getRecommendations('fakeWidgetId')
.catch(err => {
expect(err).toBe('FAKE_ERROR_RECOS')
})
})
})
})

0 comments on commit 1a11c79

Please sign in to comment.