Skip to content

Commit 645738e

Browse files
committed
test: added test coverage
1 parent ac5254f commit 645738e

8 files changed

Lines changed: 186 additions & 12 deletions

File tree

.cache/test.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"test": 1
3+
}

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,11 @@
33
"editor.defaultFormatter": "esbenp.prettier-vscode",
44
"editor.codeActionsOnSave": {
55
"source.fixAll.eslint": "explicit"
6+
},
7+
"jest.outputConfig": { "revealWithFocus": "none" },
8+
"jest.autoRun": {
9+
"watch": false,
10+
"onSave": "test-file",
11+
"onStartup": false
612
}
713
}

jest.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ const config: Config.InitialOptions = {
1212
},
1313
],
1414
},
15+
transformIgnorePatterns: ['node_modules'],
16+
prettierPath: require.resolve('prettier-2'),
1517
}
1618
export default config

package-lock.json

Lines changed: 45 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"dependencies": {
4545
"@aws-sdk/client-s3": "^3.391.0",
4646
"glob": "^10.3.10",
47-
"mime": "^4.0.1"
47+
"mime": "^3.0.0"
4848
},
4949
"devDependencies": {
5050
"@commitlint/cli": "^18.4.3",
@@ -53,6 +53,7 @@
5353
"@makerx/prettier-config": "^2.0.0",
5454
"@makerx/ts-config": "^1.0.1",
5555
"@types/jest": "^29.5.11",
56+
"@types/mime": "^3.0.4",
5657
"@types/node": "^18.13.0",
5758
"@typescript-eslint/eslint-plugin": "^6.15.0",
5859
"@typescript-eslint/parser": "^6.15.0",
@@ -65,6 +66,7 @@
6566
"jest": "^29.7.0",
6667
"npm-run-all": "^4.1.5",
6768
"prettier": "^3.1.1",
69+
"prettier-2": "npm:prettier@^2",
6870
"rimraf": "^5.0.5",
6971
"semantic-release": "^22.0.12",
7072
"ts-jest": "^29.1.1",

src/fileSystemObjectCache.spec.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { describe, beforeEach, test } from '@jest/globals'
2+
import path from 'node:path'
3+
import * as fs from 'node:fs/promises'
4+
import { FileSystemObjectCache } from './fileSystemObjectCache'
5+
6+
const testDir = path.join(__dirname, '..', '.cache')
7+
8+
describe('FileSystemObjectCache', () => {
9+
beforeEach(async () => {
10+
if (await fs.stat(testDir).catch(() => false)) {
11+
await fs.rm(testDir, { force: true, recursive: true })
12+
}
13+
})
14+
15+
test('Creates the directory when instantiated', async () => {
16+
new FileSystemObjectCache(testDir, true)
17+
expect(await fs.stat(testDir).catch(() => false)).toBeTruthy()
18+
})
19+
20+
test('Puts an object in cache as json', async () => {
21+
const cache = new FileSystemObjectCache(testDir, true)
22+
23+
await cache.put('test', { test: 1 })
24+
25+
const data = await fs.readFile(path.join(testDir, 'test.json'), { encoding: 'utf-8' })
26+
expect(data).toMatchInlineSnapshot(`
27+
"{
28+
"test": 1
29+
}"
30+
`)
31+
})
32+
33+
test("Get an object from cache if it didn't exist", async () => {
34+
const cache = new FileSystemObjectCache(testDir, true)
35+
36+
const cached = await cache.getAndCache<{ test: number }>('test', async (_) => ({
37+
test: 1,
38+
}))
39+
40+
expect(cached.test).toBe(1)
41+
})
42+
43+
test('Get an object from cache if it did exist', async () => {
44+
const cache = new FileSystemObjectCache(testDir, true)
45+
await cache.put('test', { test: 1 })
46+
47+
const cached = await cache.getAndCache<{ test: number }>('test', async (_) => ({
48+
test: 2,
49+
}))
50+
51+
expect(cached.test).toBe(1)
52+
})
53+
54+
test('Get an object from cache if it is not yet stale', async () => {
55+
const cache = new FileSystemObjectCache(testDir, true)
56+
await cache.put('test', { test: 1 })
57+
await new Promise((resolve) => setTimeout(resolve, 100))
58+
59+
const cached = await cache.getAndCache<{ test: number }>(
60+
'test',
61+
async (_) => ({
62+
test: 2,
63+
}),
64+
{ staleAfterSeconds: 2 },
65+
)
66+
67+
expect(cached.test).toBe(1)
68+
})
69+
70+
test('Get a fresh object if it is stale', async () => {
71+
const cache = new FileSystemObjectCache(testDir, true)
72+
await cache.put('test', { test: 1 })
73+
await new Promise((resolve) => setTimeout(resolve, 100))
74+
75+
const cached = await cache.getAndCache<{ test: number }>(
76+
'test',
77+
async (_) => ({
78+
test: 2,
79+
}),
80+
{ staleAfterSeconds: 0 },
81+
)
82+
83+
expect(cached.test).toBe(2)
84+
})
85+
86+
test('Get an object from cache if it is stale but there is an error and returnStaleOnError is set', async () => {
87+
const cache = new FileSystemObjectCache(testDir, true)
88+
await cache.put('test', { test: 1 })
89+
await new Promise((resolve) => setTimeout(resolve, 100))
90+
91+
const cached = await cache.getAndCache<{ test: number }>(
92+
'test',
93+
async (_) => {
94+
throw new Error('error')
95+
},
96+
{
97+
staleAfterSeconds: 0,
98+
returnStaleResultOnError: true,
99+
},
100+
)
101+
102+
expect(cached.test).toBe(1)
103+
})
104+
105+
test('Throw an error if it is stale and there is an error refreshing', async () => {
106+
const cache = new FileSystemObjectCache(testDir, true)
107+
await cache.put('test', { test: 1 })
108+
await new Promise((resolve) => setTimeout(resolve, 100))
109+
110+
await expect(() =>
111+
cache.getAndCache<{ test: number }>(
112+
'test',
113+
async (_) => {
114+
throw new Error('_ERROR_')
115+
},
116+
{
117+
staleAfterSeconds: 0,
118+
},
119+
),
120+
).rejects.toThrow('_ERROR_')
121+
})
122+
})

src/fileSystemObjectCache.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ export class FileSystemObjectCache implements ObjectCache {
6363
)
6464
const existingCache = await fs.stat(cachePath).catch((_e) => false)
6565
const expired =
66-
staleAfterSeconds && typeof existingCache !== 'boolean' && (+new Date() - +existingCache.mtime) / 1000 > staleAfterSeconds
66+
staleAfterSeconds !== undefined &&
67+
typeof existingCache !== 'boolean' &&
68+
(+new Date() - +existingCache.mtime) / 1000 > staleAfterSeconds
6769

6870
if (!existingCache || expired) {
6971
// eslint-disable-next-line no-console

src/s3ObjectCache.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ export class S3ObjectCache implements ObjectCache {
6464
.send(new GetObjectCommand(bucketAndKey))
6565
.then(async (x) => ({ Body: await x.Body!.transformToByteArray(), LastModified: x.LastModified, ContentType: x.ContentType }))
6666
.catch(() => undefined)
67-
const expired = staleAfterSeconds && existingCache && (+new Date() - +existingCache.LastModified!) / 1000 > staleAfterSeconds
67+
const expired =
68+
staleAfterSeconds !== undefined && existingCache && (+new Date() - +existingCache.LastModified!) / 1000 > staleAfterSeconds
6869

6970
if (mimeType === undefined) {
7071
mimeType = existingCache?.ContentType ?? 'application/octet-stream'

0 commit comments

Comments
 (0)