Skip to content

Commit b7f02d7

Browse files
committed
chore: improve getTsconfigWithContext test coverage
1 parent 7001484 commit b7f02d7

File tree

2 files changed

+123
-6
lines changed

2 files changed

+123
-6
lines changed

src/utils/export-map.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const parseComment = (comment: string): commentParser.Block => {
9090
}
9191
}
9292

93-
function getTsconfigWithContext(context: ChildContext | RuleContext) {
93+
export function getTsconfigWithContext(context: ChildContext | RuleContext) {
9494
const parserOptions = context.parserOptions || {}
9595
let tsconfigRootDir = parserOptions.tsconfigRootDir
9696
const project = parserOptions.project
@@ -99,7 +99,11 @@ function getTsconfigWithContext(context: ChildContext | RuleContext) {
9999
if (tsconfigCache.has(cacheKey)) {
100100
tsConfig = tsconfigCache.get(cacheKey)!
101101
} else {
102-
tsconfigRootDir = tsconfigRootDir || process.cwd()
102+
tsconfigRootDir =
103+
tsconfigRootDir ||
104+
// TODO: uncomment in next major
105+
// || context.cwd
106+
process.cwd()
103107
let tsconfigResult: TsConfigResult | null | undefined
104108
if (project) {
105109
const projects = Array.isArray(project) ? project : [project]

test/utils/export-map.spec.ts

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import fs from 'node:fs'
2+
import path from 'node:path'
23
import { setTimeout } from 'node:timers/promises'
34

45
import { jest } from '@jest/globals'
56
import * as getTsconfig from 'get-tsconfig'
67

7-
import { TEST_FILENAME, testFilePath } from '../utils.js'
8+
import {
9+
FIXTURES_PATH,
10+
TEST_FILENAME,
11+
testContext,
12+
testFilePath,
13+
} from '../utils.js'
814

915
import type { ChildContext, RuleContext } from 'eslint-plugin-import-x'
1016
import {
1117
ExportMap,
1218
isMaybeUnambiguousModule,
1319
} from 'eslint-plugin-import-x/utils'
20+
import type { getTsconfigWithContext as getTsconfigWithContext_ } from 'eslint-plugin-import-x/utils'
1421

1522
function jsdocTests(parseContext: ChildContext, lineEnding: string) {
1623
describe('deprecated imports', () => {
@@ -110,12 +117,18 @@ function jsdocTests(parseContext: ChildContext, lineEnding: string) {
110117
})
111118
}
112119

120+
const createContext = (
121+
parserOptions: RuleContext['languageOptions']['parserOptions'] = {},
122+
): RuleContext => ({
123+
...testContext(),
124+
parserOptions,
125+
})
126+
113127
describe('ExportMap', () => {
114128
const fakeContext = {
115-
physicalFilename: TEST_FILENAME,
116-
settings: {},
129+
...testContext(),
117130
parserPath: '@babel/eslint-parser',
118-
} as RuleContext
131+
}
119132

120133
it('handles ExportAllDeclaration', () => {
121134
const imports = ExportMap.get('./export-all', fakeContext)!
@@ -514,4 +527,104 @@ describe('ExportMap', () => {
514527
})
515528
}
516529
})
530+
531+
describe('getTsconfigWithContext', () => {
532+
let spied: jest.Mock
533+
534+
let getTsconfigWithContext: typeof getTsconfigWithContext_
535+
536+
const mockTsConfig: getTsconfig.TsConfigJsonResolved = {
537+
compilerOptions: { esModuleInterop: true },
538+
}
539+
540+
beforeEach(async () => {
541+
jest.resetModules()
542+
spied = jest.fn().mockReturnValue({ config: mockTsConfig })
543+
jest.unstable_mockModule('get-tsconfig', () => ({
544+
...getTsconfig,
545+
getTsconfig: spied,
546+
}))
547+
;({ getTsconfigWithContext } = await import(
548+
'eslint-plugin-import-x/utils'
549+
))
550+
})
551+
552+
afterAll(() => {
553+
spied.mockRestore()
554+
})
555+
556+
test('caches and returns the result for the same context', () => {
557+
// First call should use getTsconfig
558+
const result1 = getTsconfigWithContext(fakeContext)
559+
expect(spied).toHaveBeenCalledTimes(1)
560+
expect(result1).toBe(mockTsConfig)
561+
562+
// Second call should use the cache
563+
const result2 = getTsconfigWithContext(fakeContext)
564+
expect(spied).toHaveBeenCalledTimes(1) // Still 1
565+
expect(result2).toBe(mockTsConfig)
566+
})
567+
568+
// TODO: enable in next major
569+
test.skip('falls back to cwd when tsconfigRootDir is not provided', () => {
570+
getTsconfigWithContext(fakeContext)
571+
expect(spied).toHaveBeenCalledWith(FIXTURES_PATH)
572+
})
573+
574+
test('uses tsconfigRootDir when provided', () => {
575+
const tsconfigRootDir = '/custom/root/dir'
576+
getTsconfigWithContext(createContext({ tsconfigRootDir }))
577+
expect(spied).toHaveBeenCalledWith(tsconfigRootDir)
578+
})
579+
580+
test('resolves single project string path', () => {
581+
const tsconfigRootDir = '/custom/root/dir'
582+
const project = 'tsconfig.custom.json'
583+
getTsconfigWithContext(createContext({ tsconfigRootDir, project }))
584+
expect(spied).toHaveBeenCalledWith(path.resolve(tsconfigRootDir, project))
585+
})
586+
587+
test('uses physicalFilename when project is true', () => {
588+
const context = createContext({ project: true })
589+
getTsconfigWithContext(context)
590+
expect(spied).toHaveBeenCalledWith(TEST_FILENAME)
591+
})
592+
593+
test('tries multiple projects until finding a valid one', () => {
594+
const tsconfigRootDir = '/custom/root/dir'
595+
const projects = ['invalid.json', 'also-invalid.json', 'valid.json']
596+
const context = createContext({ tsconfigRootDir, project: projects })
597+
598+
// Mock first two calls to return null (not found)
599+
spied
600+
.mockReturnValueOnce(null)
601+
.mockReturnValueOnce(null)
602+
.mockReturnValueOnce({ config: mockTsConfig })
603+
604+
const result = getTsconfigWithContext(context)
605+
606+
// Should have tried all three paths
607+
expect(spied).toHaveBeenNthCalledWith(
608+
1,
609+
path.resolve(tsconfigRootDir, projects[0]),
610+
)
611+
expect(spied).toHaveBeenNthCalledWith(
612+
2,
613+
path.resolve(tsconfigRootDir, projects[1]),
614+
)
615+
expect(spied).toHaveBeenNthCalledWith(
616+
3,
617+
path.resolve(tsconfigRootDir, projects[2]),
618+
)
619+
620+
expect(result).toBe(mockTsConfig)
621+
})
622+
623+
test('returns undefined when no tsconfig is found', () => {
624+
// Mock getTsconfig to return null (not found)
625+
spied.mockReturnValue(null)
626+
const result = getTsconfigWithContext(fakeContext)
627+
expect(result).toBeUndefined()
628+
})
629+
})
517630
})

0 commit comments

Comments
 (0)