Skip to content

Commit

Permalink
Merge pull request #540 from shopgate/PWA-1703-6.2
Browse files Browse the repository at this point in the history
Wrong page tracked when user comes back after checkout
  • Loading branch information
fkloes committed Feb 15, 2019
2 parents 871fc9b + 4cfb506 commit 400da33
Show file tree
Hide file tree
Showing 14 changed files with 125 additions and 88 deletions.
2 changes: 2 additions & 0 deletions libraries/common/reducers/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ROUTE_DID_LEAVE,
ROUTE_WILL_LEAVE,
ROUTE_DID_UPDATE,
ROUTE_DID_ENTER,
} from '../../constants/ActionTypes';

const defaultState = {
Expand All @@ -27,6 +28,7 @@ export default function router(state = defaultState, action) {
};
}
case ROUTE_WILL_ENTER:
case ROUTE_DID_ENTER:
return {
...state,
stack: Array.from(stack.getAll().values()),
Expand Down
1 change: 1 addition & 0 deletions libraries/common/streams/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'rxjs/add/operator/do';
import 'rxjs/add/operator/shareReplay';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/withLatestFrom';
import { mainSubject } from '../store/middelwares/streams';

/**
Expand Down
13 changes: 12 additions & 1 deletion libraries/tracking/action-creators/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { PWA_DID_APPEAR } from '../constants';
import {
PWA_DID_APPEAR,
PWA_DID_DISAPPEAR,
} from '../constants';

/**
* Creates the dispatched PWA_DID_APPEAR action object.
Expand All @@ -7,3 +10,11 @@ import { PWA_DID_APPEAR } from '../constants';
export const pwaDidAppear = () => ({
type: PWA_DID_APPEAR,
});

/**
* Creates the dispatched PWA_DID_DISAPPEAR action
* @return {Object} The dispatched action object.
*/
export const pwaDidDisappear = () => ({
type: PWA_DID_DISAPPEAR,
});
2 changes: 2 additions & 0 deletions libraries/tracking/constants/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const APP_EVENT_VIEW_DID_APPEAR = 'viewDidAppear';
export const APP_EVENT_VIEW_DID_DISAPPEAR = 'viewDidDisappear';

export const PWA_DID_APPEAR = 'PWA_DID_APPEAR';
export const PWA_DID_DISAPPEAR = 'PWA_DID_DISAPPEAR';
24 changes: 1 addition & 23 deletions libraries/tracking/helpers/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import get from 'lodash/get';
import find from 'lodash/find';
import core from '@shopgate/tracking-core/core/Core';
import { logger, hasSGJavaScriptBridge } from '@shopgate/pwa-core/helpers';
import { logger } from '@shopgate/pwa-core/helpers';

/**
* Converts a price to a formatted string.
Expand Down Expand Up @@ -164,25 +164,3 @@ export const track = (eventName, data, state) => {

return core;
};

/**
* Initialize the visible state. When the PWA runs within a real app, it will be set to TRUE when
* the app sends the APP_EVENT_VIEW_DID_APPEAR event. Within a browser it needs to be set manually.
* Otherwise page tracking would be suprpessed.
*/
let pwaWebviewVisible = !hasSGJavaScriptBridge();

/**
* Sets the visible state of the PWA webview.
* It's used to determine, if a legacy page is currently active.
* @param {boolean} [value=true] Tells if the PWA currently visible.
*/
export const setPWAVisibleState = (value = true) => {
pwaWebviewVisible = value;
};

/**
* Checks if the PWA webview is currently visible.
* @return {boolean}
*/
export const isPWAVisible = () => pwaWebviewVisible;
26 changes: 0 additions & 26 deletions libraries/tracking/helpers/index.spec.js

This file was deleted.

23 changes: 22 additions & 1 deletion libraries/tracking/streams/app.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { getCurrentRoute } from '@shopgate/pwa-common/selectors/router';
import { main$ } from '@shopgate/pwa-common/streams/main';
import { PWA_DID_APPEAR } from '../constants';
import {
PWA_DID_APPEAR,
PWA_DID_DISAPPEAR,
} from '../constants';

/**
* Emits when the PWA appeared again after navigating back from a legacy page.
Expand All @@ -14,3 +17,21 @@ export const pwaDidAppear$ = main$
route: getCurrentRoute(params.getState()),
},
}));

/**
* Emits when the PWA disappears
*/
export const pwaDidDisappear$ = main$
.filter(({ action }) => action.type === PWA_DID_DISAPPEAR)
.map(params => ({
...params,
action: {
...params.action,
route: getCurrentRoute(params.getState()),
},
}));

/**
* Emits when the PWA visibility changes
*/
export const pwaVisibility$ = pwaDidAppear$.merge(pwaDidDisappear$);
8 changes: 3 additions & 5 deletions libraries/tracking/streams/checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { navigate$ } from '@shopgate/pwa-common/streams/router';
import { isUserLoggedIn } from '@shopgate/pwa-common/selectors/user';
import { CHECKOUT_PATH } from '@shopgate/pwa-common/constants/RoutePaths';

const actionsWl = [ACTION_PUSH, ACTION_REPLACE];

export const checkoutDidEnter$ = navigate$
.filter(({ action, getState }) => {
if (action.params.pathname !== CHECKOUT_PATH) {
Expand All @@ -21,9 +23,5 @@ export const checkoutDidEnter$ = navigate$
* A checkout route can be pushed when a logged in user opens the checkout. It can also replace
* the current route when a user is redirected from the login form after a successful login.
*/
if ([ACTION_PUSH, ACTION_REPLACE].includes(navigateAction)) {
return true;
}

return false;
return actionsWl.includes(navigateAction);
});
37 changes: 30 additions & 7 deletions libraries/tracking/streams/pages.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { routeDidEnter$ } from '@shopgate/pwa-common/streams/router';
import { appWillStart$ } from '@shopgate/pwa-common/streams/app';
import { APP_WILL_START } from '@shopgate/pwa-common/constants/ActionTypes';
import {
SEARCH_PATH,
SEARCH_FILTER_PATTERN,
Expand All @@ -15,11 +17,16 @@ import {
ITEM_WRITE_REVIEW_PATTERN,
} from '@shopgate/pwa-common-commerce/product/constants';
import { FAVORITES_PATH } from '@shopgate/pwa-common-commerce/favorites/constants';
import { pwaDidAppear$ } from './app';
import { isPWAVisible } from '../helpers';
import { PWA_DID_APPEAR } from '../constants';
import {
pwaDidAppear$,
pwaDidDisappear$,
pwaVisibility$,
} from './app';
import { checkoutDidEnter$ } from './checkout';

/**
* A blacklist of paths that should be tracked whithin their individual subscriptions.
* A blacklist of paths that should be tracked within their individual subscriptions.
* @type {Array}
*/
export const blacklistedPatterns = [
Expand All @@ -36,10 +43,26 @@ export const blacklistedPatterns = [
ITEM_WRITE_REVIEW_PATTERN,
];

const latestAppActions$ = appWillStart$.merge(pwaVisibility$, checkoutDidEnter$);

/**
* Route did enter and PWA is visible and route is not blacklisted
* @type {Rx.Observable<*[]>}
*/
const routeDidEnterForVisiblePwa$ = routeDidEnter$
.withLatestFrom(latestAppActions$)
.filter(([, { action: { type } }]) => type === APP_WILL_START || type === PWA_DID_APPEAR)
.map(([routeDidEnter]) => routeDidEnter);

/**
* PWA reappear after disappear
* @type {Rx.Observable<any>}
*/
const pwaDidAppearAfterDisappear = pwaDidDisappear$.switchMap(() => pwaDidAppear$.first());

/**
* Emits when one of the tracked paths is entered except some special one.
* Emits when one of the tracked paths is entered or pwa reappear
*/
export const pagesAreReady$ = routeDidEnter$
.filter(() => isPWAVisible())
.merge(pwaDidAppear$)
export const pagesAreReady$ = routeDidEnterForVisiblePwa$
.merge(pwaDidAppearAfterDisappear)
.filter(({ action }) => !blacklistedPatterns.find(pattern => action.route.pattern === pattern));
55 changes: 46 additions & 9 deletions libraries/tracking/streams/pages.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { combineReducers } from 'redux';
import { ACTION_REPLACE } from '@virtuous/conductor';
import { createMockStore } from '@shopgate/pwa-common/store';
import { routeDidEnter } from '@shopgate/pwa-common/action-creators/router';
import { setPWAVisibleState } from '../helpers';
import { pwaDidAppear } from '../action-creators';
import user from '@shopgate/pwa-common/reducers/user';
import { routeDidEnter, navigate } from '@shopgate/pwa-common/action-creators/router';
import { appWillStart } from '@shopgate/pwa-common/action-creators/app';
import { CHECKOUT_PATH } from '@shopgate/pwa-common/constants/RoutePaths';
import {
pwaDidAppear,
pwaDidDisappear,
} from '../action-creators';
import { blacklistedPatterns, pagesAreReady$ } from './pages';

let mockedPattern;
Expand Down Expand Up @@ -32,18 +39,19 @@ describe('Page streams', () => {
jest.clearAllMocks();

mockedPattern = '';
({ dispatch } = createMockStore());
({ dispatch } = createMockStore(combineReducers({ user })));

pagesAreReadySubscriber = jest.fn();
pagesAreReady$.subscribe(pagesAreReadySubscriber);
});

describe('pagesAreReady$', () => {
beforeEach(() => {
setPWAVisibleState(true);
// Simulate app is started
dispatch(appWillStart('/'));
});

it('should emit when a route is active which is not blacklisted', () => {
it('should emit when a route not blacklisted', () => {
dispatch(routeDidEnterWrapped('/somepath'));
expect(pagesAreReadySubscriber).toHaveBeenCalledTimes(1);
});
Expand All @@ -54,23 +62,52 @@ describe('Page streams', () => {
});

it('should not emit when a route is active, but the PWA is not visible', () => {
setPWAVisibleState(false);
// Simulate pwa is disappear
dispatch(pwaDidDisappear());

dispatch(routeDidEnterWrapped('/somepath'));
expect(pagesAreReadySubscriber).not.toHaveBeenCalled();

// Simulate pwa is appeared again
dispatch(pwaDidAppear());
expect(pagesAreReadySubscriber).toHaveBeenCalledTimes(1);
});
});

describe('coming back from legacy pages', () => {
it('should emit when pwaDidAppear is dispatched and a not blacklisted route is active', () => {
beforeEach(() => {
// Simulate app is started
dispatch(appWillStart('/'));
});
it('should emit when PWA is reappear and a not blacklisted route is active', () => {
dispatch(routeDidEnterWrapped('/somepath'));
dispatch(pwaDidDisappear());
dispatch(pwaDidAppear());
expect(pagesAreReadySubscriber).toHaveBeenCalledTimes(1);
expect(pagesAreReadySubscriber).toHaveBeenCalledTimes(2);
});

it('should not emit when pwaDidAppear is dispatched and a blacklisted is active', () => {
dispatch(routeDidEnterWrapped(blacklistedPatterns[0]));
dispatch(pwaDidDisappear());
dispatch(pwaDidAppear());
expect(pagesAreReadySubscriber).not.toHaveBeenCalled();
});
});

describe('go to checkout', () => {
beforeEach(() => {
// Simulate app is started
dispatch(appWillStart('/'));
});
it('should not emit events when user goes to checkout', () => {
dispatch(routeDidEnterWrapped('/somepath'));
dispatch(navigate({
action: ACTION_REPLACE,
pathname: CHECKOUT_PATH,
}));
// should not track this path
dispatch(routeDidEnterWrapped('/somepath2'));
expect(pagesAreReadySubscriber).toHaveBeenCalledTimes(1);
});
});
});
4 changes: 1 addition & 3 deletions libraries/tracking/subscriptions/checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import event from '@shopgate/pwa-core/classes/Event';
import analyticsSetCustomValues from '@shopgate/pwa-core/commands/analyticsSetCustomValues';
import { appDidStart$ } from '@shopgate/pwa-common/streams/app';
import getCart from '../selectors/cart';
import { track, formatPurchaseData, setPWAVisibleState } from '../helpers';
import { track, formatPurchaseData } from '../helpers';
import { checkoutDidEnter$ } from '../streams/checkout';

/**
Expand All @@ -11,8 +11,6 @@ import { checkoutDidEnter$ } from '../streams/checkout';
*/
export default function checkout(subscribe) {
subscribe(checkoutDidEnter$, ({ getState }) => {
setPWAVisibleState(false);

const state = getState();

track('initiatedCheckout', { cart: getCart(state) }, state);
Expand Down
4 changes: 0 additions & 4 deletions libraries/tracking/subscriptions/checkout.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ describe('Checkout subscriptions', () => {
});

it('should call the expected commands', () => {
const setPWAVisibleStateSpy = jest.spyOn(helpers, 'setPWAVisibleState');
const trackSpy = jest.spyOn(helpers, 'track');
/**
* Mocked getState function.
Expand All @@ -45,9 +44,6 @@ describe('Checkout subscriptions', () => {
{ cart: getCart(getState()) },
getState()
);

expect(setPWAVisibleStateSpy).toHaveBeenCalledTimes(1);
expect(setPWAVisibleStateSpy).toHaveBeenCalledWith(false);
});
});
});
9 changes: 5 additions & 4 deletions libraries/tracking/subscriptions/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import {
} from '@shopgate/pwa-common/streams/app';
import UnifiedPlugin from '@shopgate/tracking-core/plugins/trackers/Unified';
import { APP_EVENT_VIEW_DID_APPEAR, APP_EVENT_VIEW_DID_DISAPPEAR } from '../constants';
import { pwaDidAppear } from '../action-creators';
import { setPWAVisibleState } from '../helpers';
import {
pwaDidAppear,
pwaDidDisappear,
} from '../action-creators';

/**
* Setup tracking subscriptions.
Expand All @@ -29,12 +31,11 @@ export default function setup(subscribe) {
]);

event.addCallback(APP_EVENT_VIEW_DID_APPEAR, () => {
setPWAVisibleState(true);
dispatch(pwaDidAppear());
});

event.addCallback(APP_EVENT_VIEW_DID_DISAPPEAR, () => {
setPWAVisibleState(false);
dispatch(pwaDidDisappear());
});
});

Expand Down
Loading

0 comments on commit 400da33

Please sign in to comment.