Skip to content

Commit

Permalink
Merge pull request #1208 from searchspring/backforwardcache
Browse files Browse the repository at this point in the history
Recommendation Back/Forward Cache
  • Loading branch information
korgon authored Dec 4, 2024
2 parents e414bd0 + 54c995e commit 2099968
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { EventManager } from '@searchspring/snap-event-manager';
import { Profiler } from '@searchspring/snap-profiler';
import { Logger } from '@searchspring/snap-logger';
import { MockClient } from '@searchspring/snap-shared';

import { waitFor } from '@testing-library/preact';
import { RecommendationController } from './RecommendationController';

const globals = { siteId: '8uyt2m' };
Expand Down Expand Up @@ -118,6 +118,135 @@ describe('Recommendation Controller', () => {
});
});

it(`tests searchOnPageShow triggers search on persisted pageshow event `, async function () {
const controller = new RecommendationController(recommendConfig, {
client: new MockClient(globals, {}),
store: new RecommendationStore(recommendConfig, services),
urlManager,
eventManager: new EventManager(),
profiler: new Profiler(),
logger: new Logger(),
tracker: new Tracker(globals),
});

await controller.search();

const searchSpy = jest.spyOn(controller, 'search');

expect(searchSpy).not.toHaveBeenCalled();

// Mock PageTransitionEvent
class MockPageTransitionEvent extends Event {
public persisted: boolean;

constructor(type: string, eventInitDict?: EventInit & { persisted?: boolean }) {
super(type, eventInitDict);
this.persisted = eventInitDict?.persisted ?? false;
}
}

const event = new MockPageTransitionEvent('pageshow', {
bubbles: true,
persisted: true,
});

window.dispatchEvent(event);

await waitFor(() => {
expect(searchSpy).toHaveBeenCalled();
});
});

it(`can turn off searchOnPageShow`, async function () {
const customConfig = {
...recommendConfig,
settings: {
searchOnPageShow: false,
},
};
const controller = new RecommendationController(customConfig, {
client: new MockClient(globals, {}),
store: new RecommendationStore(recommendConfig, services),
urlManager,
eventManager: new EventManager(),
profiler: new Profiler(),
logger: new Logger(),
tracker: new Tracker(globals),
});

await controller.search();

const searchSpy = jest.spyOn(controller, 'search');

expect(searchSpy).not.toHaveBeenCalled();

// Mock PageTransitionEvent
class MockPageTransitionEvent extends Event {
public persisted: boolean;

constructor(type: string, eventInitDict?: EventInit & { persisted?: boolean }) {
super(type, eventInitDict);
this.persisted = eventInitDict?.persisted ?? false;
}
}

const event = new MockPageTransitionEvent('pageshow', {
bubbles: true,
persisted: true,
});

window.dispatchEvent(event);

await waitFor(() => {
expect(searchSpy).not.toHaveBeenCalled();
});
});

it(`tests searchOnPageShow doesnt trigger search if persisted is false or undefined on the pageshow event`, async function () {
const controller = new RecommendationController(recommendConfig, {
client: new MockClient(globals, {}),
store: new RecommendationStore(recommendConfig, services),
urlManager,
eventManager: new EventManager(),
profiler: new Profiler(),
logger: new Logger(),
tracker: new Tracker(globals),
});

await controller.search();

const searchSpy = jest.spyOn(controller, 'search');

expect(searchSpy).not.toHaveBeenCalled();

// Mock PageTransitionEvent
class MockPageTransitionEvent extends Event {
public persisted: boolean;

constructor(type: string, eventInitDict?: EventInit & { persisted?: boolean }) {
super(type, eventInitDict);
this.persisted = eventInitDict?.persisted ?? false;
}
}

const event = new MockPageTransitionEvent('pageshow', {
bubbles: true,
persisted: false,
});

window.dispatchEvent(event);

const event2 = new MockPageTransitionEvent('pageshow', {
bubbles: true,
});

window.dispatchEvent(event2);

await waitFor(() => {
expect(searchSpy).not.toHaveBeenCalled();
});
});

it('can invoke controller track.click and track.product.click', async () => {
const controller = new RecommendationController(recommendConfig, {
client: new MockClient(globals, {}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ export class RecommendationController extends AbstractController {
throw new Error(`Invalid config passed to RecommendationController. The "tag" attribute is required.`);
}

// attach to bfCache restore event and re-run search on the controller
// enabled by default
if (config.settings?.searchOnPageShow !== false) {
window.addEventListener('pageshow', (e) => {
if (e.persisted && !this.store.error && this.store.loaded && !this.store.loading) {
this.search();
}
});
}

// deep merge config with defaults
this.config = deepmerge(defaultConfig, this.config);
this.store.setConfig(this.config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { cookies } from '@searchspring/snap-toolbox';
import { Logger } from '@searchspring/snap-logger';
import { MockClient } from '@searchspring/snap-shared';
import { Next } from '@searchspring/snap-event-manager';
import { waitFor } from '@testing-library/preact';

const DEFAULT_PROFILE = 'trending';
const CART_COOKIE = 'ssCartProducts';
Expand Down Expand Up @@ -936,4 +937,45 @@ describe('RecommendationInstantiator', () => {
expect(plugin2).toHaveBeenCalledWith(controller);
});
});

it(`searchOnPageShow triggers search on persisted pageshow event `, async function () {
document.body.innerHTML = `<script type="searchspring/recommend" profile="${DEFAULT_PROFILE}"></script>`;

const attachmentConfig = {
...baseConfig,
config: {
branch: baseConfig.config.branch,
},
};

const client = new MockClient(baseConfig.client!.globals, {});
const recommendationInstantiator = new RecommendationInstantiator(attachmentConfig as RecommendationInstantiatorConfig, { client });
await wait();

Object.keys(recommendationInstantiator.controller).forEach(async (controllerId) => {
const controller = recommendationInstantiator.controller[controllerId];
const searchSpy = jest.spyOn(controller, 'search');
expect(searchSpy).not.toHaveBeenCalled();

// Mock PageTransitionEvent
class MockPageTransitionEvent extends Event {
public persisted: boolean;

constructor(type: string, eventInitDict?: EventInit & { persisted?: boolean }) {
super(type, eventInitDict);
this.persisted = eventInitDict?.persisted ?? false;
}
}
const event = new MockPageTransitionEvent('pageshow', {
bubbles: true,
persisted: true,
});

window.dispatchEvent(event);

await waitFor(() => {
expect(searchSpy).toHaveBeenCalled();
});
});
});
});
1 change: 1 addition & 0 deletions packages/snap-store-mobx/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export type RecommendationStoreConfig = StoreConfig & {
batchId?: number;
settings?: {
variants?: VariantConfig;
searchOnPageShow: boolean;
};
};

Expand Down

0 comments on commit 2099968

Please sign in to comment.