Skip to content

Commit

Permalink
feat: introduce getVisitorDataFromCache and isInCache options
Browse files Browse the repository at this point in the history
  • Loading branch information
TheUnderScorer committed Nov 2, 2023
1 parent c101318 commit a9aa598
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,15 @@ const result = await fpjsClient.getVisitorData({ extendedResult: true })

// true if cache was hit
console.log(result.cacheHit)
```

You can also use the following API to retrieve responses from cache:
```js
// Checks if request matching given options is present in cache
await fpjsClient.isInCache({ extendedResult: true })

// Returns cached visitor data based on the request options, or undefined if the data is not present in cache
const cachedResult = await fpjsClient.getVisitorDataFromCache({ extendedResult: true })
```

#### Creating a custom cache
Expand Down
89 changes: 89 additions & 0 deletions __tests__/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,95 @@ describe(`SPA client`, () => {
})
})

describe('getVisitorDataFromCache', () => {
const mockVisitorId = 'abc123'
const cachePrefix = 'get_visitor_data_from_cache_test'
let agentGetMock: jest.Mock

beforeEach(() => {
agentGetMock = jest.fn(async () => {
return {
visitorId: mockVisitorId,
} as FingerprintJS.GetResult
})
// @ts-ignore
jest.spyOn(FingerprintJS, 'load').mockImplementation(async () => {
return {
get: agentGetMock,
}
})
})

afterEach(() => {
localStorage.clear()
})

it('should return response if it is cached, and undefined if it is not', async () => {
const client = new FpjsClient({
loadOptions: getDefaultLoadOptions(),
cacheLocation: CacheLocation.LocalStorage,
cachePrefix,
})
await client.init()

const response = await client.getVisitorData()

const cachedResponse = await client.getVisitorDataFromCache()

expect(cachedResponse).toEqual({
...response,
cacheHit: true,
})

expect(agentGetMock).toHaveBeenCalledTimes(1)

const notCachedResponse = await client.getVisitorDataFromCache({ extendedResult: true })

expect(notCachedResponse).toBeUndefined()
})
})

describe('isInCache', () => {
const mockVisitorId = 'abc123'
const cachePrefix = 'is_in_cache_test'
let agentGetMock: jest.Mock

beforeEach(() => {
agentGetMock = jest.fn(async () => {
return {
visitorId: mockVisitorId,
} as FingerprintJS.GetResult
})
// @ts-ignore
jest.spyOn(FingerprintJS, 'load').mockImplementation(async () => {
return {
get: agentGetMock,
}
})
})

afterEach(() => {
localStorage.clear()
})

it('should return true if response is cached', async () => {
const client = new FpjsClient({
loadOptions: getDefaultLoadOptions(),
cacheLocation: CacheLocation.LocalStorage,
cachePrefix,
})
await client.init()

await client.getVisitorData()
await client.getVisitorData()

expect(agentGetMock).toHaveBeenCalledTimes(1)
await expect(client.isInCache()).resolves.toEqual(true)
await expect(client.isInCache({ extendedResult: true })).resolves.toEqual(false)
await expect(client.isInCache({ tag: 'tag' })).resolves.toEqual(false)
})
})

describe('getVisitorData', () => {
const mockVisitorId = 'abc123'
const cachePrefix = 'cache_test'
Expand Down
18 changes: 18 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,24 @@ export class FpjsClient {
return (await this.inFlightRequests.get(key)) as FpjsSpaResponse<VisitorData<TExtended>>
}

/**
* Returns cached visitor data based on the request options, or undefined if the data is not present in cache
* */
public async getVisitorDataFromCache<TExtended extends boolean>(
options: GetOptions<TExtended> = {}
): Promise<FpjsSpaResponse<VisitorData<TExtended>> | undefined> {
const cacheKey = FpjsClient.makeCacheKey(options)
const cacheResult = await this.cacheManager.get(cacheKey)
return cacheResult ? { ...cacheResult, cacheHit: true } : undefined
}

/**
* Checks if request matching given options is present in cache
* */
public async isInCache(options: GetOptions<boolean> = {}) {
return Boolean(await this.getVisitorDataFromCache(options))
}

/**
* Clears visitor data from cache regardless of the cache implementation
*/
Expand Down

0 comments on commit a9aa598

Please sign in to comment.