Skip to content

Commit 0280e10

Browse files
[Tests] Remove filesystem mocks in copy-source-entry.test.ts
Refactor copy-source-entry.test.ts to use real filesystem operations via inTemporaryDirectory instead of mocking @shopify/cli-kit/node/fs. This improves test fidelity and reliability.
1 parent b6642ac commit 0280e10

1 file changed

Lines changed: 184 additions & 128 deletions

File tree

Lines changed: 184 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import {copySourceEntry} from './copy-source-entry.js'
22
import {describe, expect, test, vi, beforeEach} from 'vitest'
3-
import * as fs from '@shopify/cli-kit/node/fs'
4-
5-
vi.mock('@shopify/cli-kit/node/fs')
3+
import {inTemporaryDirectory, writeFile, mkdir, fileExistsSync, readFile} from '@shopify/cli-kit/node/fs'
4+
import {joinPath} from '@shopify/cli-kit/node/path'
65

76
describe('copySourceEntry', () => {
87
let mockStdout: any
@@ -12,149 +11,206 @@ describe('copySourceEntry', () => {
1211
})
1312

1413
test('throws when source path does not exist', async () => {
15-
// Given
16-
vi.mocked(fs.fileExists).mockResolvedValue(false)
14+
await inTemporaryDirectory(async (tmpDir) => {
15+
// Given
16+
const baseDir = joinPath(tmpDir, 'ext')
17+
const outputDir = joinPath(tmpDir, 'out')
18+
const appDirectory = tmpDir
19+
await mkdir(baseDir)
20+
await mkdir(outputDir)
21+
22+
// When / Then
23+
await expect(
24+
copySourceEntry(
25+
{
26+
source: 'missing/file.js',
27+
destination: undefined,
28+
baseDir,
29+
outputDir,
30+
appDirectory,
31+
},
32+
{stdout: mockStdout},
33+
),
34+
).rejects.toThrow(`Source does not exist: ${joinPath(baseDir, 'missing/file.js')}`)
35+
})
36+
})
1737

18-
// When / Then
19-
await expect(
20-
copySourceEntry(
38+
test('copies file to explicit destination path', async () => {
39+
await inTemporaryDirectory(async (tmpDir) => {
40+
// Given
41+
const baseDir = joinPath(tmpDir, 'ext')
42+
const outputDir = joinPath(tmpDir, 'out')
43+
const appDirectory = tmpDir
44+
await mkdir(baseDir)
45+
await mkdir(outputDir)
46+
const sourceFile = joinPath(baseDir, 'src/icon.png')
47+
await mkdir(joinPath(baseDir, 'src'))
48+
await writeFile(sourceFile, 'icon-content')
49+
50+
// When
51+
const result = await copySourceEntry(
2152
{
22-
source: 'missing/file.js',
23-
destination: undefined,
24-
baseDir: '/ext',
25-
outputDir: '/out',
26-
appDirectory: '/ext',
53+
source: 'src/icon.png',
54+
destination: 'assets/icon.png',
55+
baseDir,
56+
outputDir,
57+
appDirectory,
2758
},
2859
{stdout: mockStdout},
29-
),
30-
).rejects.toThrow('Source does not exist: /ext/missing/file.js')
31-
})
32-
33-
test('copies file to explicit destination path', async () => {
34-
// Given
35-
vi.mocked(fs.fileExists).mockResolvedValue(true)
36-
vi.mocked(fs.isDirectory).mockResolvedValue(false)
37-
vi.mocked(fs.mkdir).mockResolvedValue()
38-
vi.mocked(fs.copyFile).mockResolvedValue()
39-
40-
// When
41-
const result = await copySourceEntry(
42-
{
43-
source: 'src/icon.png',
44-
destination: 'assets/icon.png',
45-
baseDir: '/ext',
46-
outputDir: '/out',
47-
appDirectory: '/ext',
48-
},
49-
{stdout: mockStdout},
50-
)
51-
52-
// Then
53-
expect(fs.copyFile).toHaveBeenCalledWith('/ext/src/icon.png', '/out/assets/icon.png')
54-
expect(result.filesCopied).toBe(1)
55-
expect(result.outputPaths).toEqual(['assets/icon.png'])
56-
expect(mockStdout.write).toHaveBeenCalledWith('Included src/icon.png\n')
60+
)
61+
62+
// Then
63+
const expectedDest = joinPath(outputDir, 'assets/icon.png')
64+
expect(fileExistsSync(expectedDest)).toBe(true)
65+
await expect(readFile(expectedDest)).resolves.toBe('icon-content')
66+
expect(result.filesCopied).toBe(1)
67+
expect(result.outputPaths).toEqual(['assets/icon.png'])
68+
expect(mockStdout.write).toHaveBeenCalledWith('Included src/icon.png\n')
69+
})
5770
})
5871

5972
test('copies directory under its own name when no destination is given', async () => {
60-
// Given
61-
vi.mocked(fs.fileExists).mockResolvedValue(true)
62-
vi.mocked(fs.isDirectory).mockResolvedValue(true)
63-
vi.mocked(fs.copyDirectoryContents).mockResolvedValue()
64-
vi.mocked(fs.glob).mockResolvedValue(['index.html', 'logo.png'])
65-
66-
// When
67-
const result = await copySourceEntry(
68-
{source: 'dist', destination: undefined, baseDir: '/ext', outputDir: '/out', appDirectory: '/ext'},
69-
{stdout: mockStdout},
70-
)
71-
72-
// Then
73-
expect(fs.copyDirectoryContents).toHaveBeenCalledWith('/ext/dist', '/out/dist')
74-
expect(result.filesCopied).toBe(2)
75-
expect(result.outputPaths).toEqual(['dist/index.html', 'dist/logo.png'])
76-
expect(mockStdout.write).toHaveBeenCalledWith('Included dist\n')
73+
await inTemporaryDirectory(async (tmpDir) => {
74+
// Given
75+
const baseDir = joinPath(tmpDir, 'ext')
76+
const outputDir = joinPath(tmpDir, 'out')
77+
const appDirectory = tmpDir
78+
await mkdir(baseDir)
79+
await mkdir(outputDir)
80+
81+
const distDir = joinPath(baseDir, 'dist')
82+
await mkdir(distDir)
83+
await writeFile(joinPath(distDir, 'index.html'), 'html')
84+
await writeFile(joinPath(distDir, 'logo.png'), 'logo')
85+
86+
// When
87+
const result = await copySourceEntry(
88+
{source: 'dist', destination: undefined, baseDir, outputDir, appDirectory},
89+
{stdout: mockStdout},
90+
)
91+
92+
// Then
93+
expect(fileExistsSync(joinPath(outputDir, 'dist/index.html'))).toBe(true)
94+
expect(fileExistsSync(joinPath(outputDir, 'dist/logo.png'))).toBe(true)
95+
expect(result.filesCopied).toBe(2)
96+
expect(result.outputPaths).toHaveLength(2)
97+
expect(result.outputPaths).toEqual(expect.arrayContaining(['dist/index.html', 'dist/logo.png']))
98+
expect(mockStdout.write).toHaveBeenCalledWith('Included dist\n')
99+
})
77100
})
78101

79102
test('copies file to basename in outputDir when source is a file and no destination given', async () => {
80-
// Given
81-
vi.mocked(fs.fileExists).mockResolvedValue(true)
82-
vi.mocked(fs.isDirectory).mockResolvedValue(false)
83-
vi.mocked(fs.mkdir).mockResolvedValue()
84-
vi.mocked(fs.copyFile).mockResolvedValue()
85-
86-
// When
87-
const result = await copySourceEntry(
88-
{source: 'README.md', destination: undefined, baseDir: '/ext', outputDir: '/out', appDirectory: '/ext'},
89-
{stdout: mockStdout},
90-
)
91-
92-
// Then
93-
expect(fs.copyFile).toHaveBeenCalledWith('/ext/README.md', '/out/README.md')
94-
expect(result.filesCopied).toBe(1)
95-
expect(result.outputPaths).toEqual(['README.md'])
96-
expect(mockStdout.write).toHaveBeenCalledWith('Included README.md\n')
103+
await inTemporaryDirectory(async (tmpDir) => {
104+
// Given
105+
const baseDir = joinPath(tmpDir, 'ext')
106+
const outputDir = joinPath(tmpDir, 'out')
107+
const appDirectory = tmpDir
108+
await mkdir(baseDir)
109+
await mkdir(outputDir)
110+
await writeFile(joinPath(baseDir, 'README.md'), 'readme')
111+
112+
// When
113+
const result = await copySourceEntry(
114+
{source: 'README.md', destination: undefined, baseDir, outputDir, appDirectory},
115+
{stdout: mockStdout},
116+
)
117+
118+
// Then
119+
const expectedDest = joinPath(outputDir, 'README.md')
120+
expect(fileExistsSync(expectedDest)).toBe(true)
121+
await expect(readFile(expectedDest)).resolves.toBe('readme')
122+
expect(result.filesCopied).toBe(1)
123+
expect(result.outputPaths).toEqual(['README.md'])
124+
expect(mockStdout.write).toHaveBeenCalledWith('Included README.md\n')
125+
})
97126
})
98127

99128
test('copies directory to explicit destination path', async () => {
100-
// Given
101-
vi.mocked(fs.fileExists).mockResolvedValue(true)
102-
vi.mocked(fs.isDirectory).mockResolvedValue(true)
103-
vi.mocked(fs.copyDirectoryContents).mockResolvedValue()
104-
vi.mocked(fs.glob).mockResolvedValue(['x.js'])
105-
106-
// When
107-
const result = await copySourceEntry(
108-
{source: 'dist', destination: 'vendor/dist', baseDir: '/ext', outputDir: '/out', appDirectory: '/ext'},
109-
{stdout: mockStdout},
110-
)
111-
112-
// Then
113-
expect(fs.copyDirectoryContents).toHaveBeenCalledWith('/ext/dist', '/out/vendor/dist')
114-
expect(result.filesCopied).toBe(1)
115-
expect(result.outputPaths).toEqual(['vendor/dist/x.js'])
116-
expect(mockStdout.write).toHaveBeenCalledWith('Included dist\n')
129+
await inTemporaryDirectory(async (tmpDir) => {
130+
// Given
131+
const baseDir = joinPath(tmpDir, 'ext')
132+
const outputDir = joinPath(tmpDir, 'out')
133+
const appDirectory = tmpDir
134+
await mkdir(baseDir)
135+
await mkdir(outputDir)
136+
137+
const distDir = joinPath(baseDir, 'dist')
138+
await mkdir(distDir)
139+
await writeFile(joinPath(distDir, 'x.js'), 'js')
140+
141+
// When
142+
const result = await copySourceEntry(
143+
{source: 'dist', destination: 'vendor/dist', baseDir, outputDir, appDirectory},
144+
{stdout: mockStdout},
145+
)
146+
147+
// Then
148+
expect(fileExistsSync(joinPath(outputDir, 'vendor/dist/x.js'))).toBe(true)
149+
expect(result.filesCopied).toBe(1)
150+
expect(result.outputPaths).toEqual(['vendor/dist/x.js'])
151+
expect(mockStdout.write).toHaveBeenCalledWith('Included dist\n')
152+
})
117153
})
118154

119155
test('returns count of files discovered in destination directory after directory copy', async () => {
120-
// Given
121-
vi.mocked(fs.fileExists).mockResolvedValue(true)
122-
vi.mocked(fs.isDirectory).mockResolvedValue(true)
123-
vi.mocked(fs.copyDirectoryContents).mockResolvedValue()
124-
// Simulate 5 files inside the copied directory
125-
vi.mocked(fs.glob).mockResolvedValue(['a.js', 'b.js', 'c.js', 'd.js', 'e.js'])
126-
127-
// When
128-
const result = await copySourceEntry(
129-
{source: 'theme', destination: undefined, baseDir: '/ext', outputDir: '/out', appDirectory: '/ext'},
130-
{stdout: mockStdout},
131-
)
132-
133-
// Then — count comes from glob on destPath, not a constant
134-
expect(result.filesCopied).toBe(5)
135-
expect(result.outputPaths).toEqual(['theme/a.js', 'theme/b.js', 'theme/c.js', 'theme/d.js', 'theme/e.js'])
156+
await inTemporaryDirectory(async (tmpDir) => {
157+
// Given
158+
const baseDir = joinPath(tmpDir, 'ext')
159+
const outputDir = joinPath(tmpDir, 'out')
160+
const appDirectory = tmpDir
161+
await mkdir(baseDir)
162+
await mkdir(outputDir)
163+
164+
const themeDir = joinPath(baseDir, 'theme')
165+
await mkdir(themeDir)
166+
await writeFile(joinPath(themeDir, 'a.js'), 'a')
167+
await writeFile(joinPath(themeDir, 'b.js'), 'b')
168+
await writeFile(joinPath(themeDir, 'c.js'), 'c')
169+
await writeFile(joinPath(themeDir, 'd.js'), 'd')
170+
await writeFile(joinPath(themeDir, 'e.js'), 'e')
171+
172+
// When
173+
const result = await copySourceEntry(
174+
{source: 'theme', destination: undefined, baseDir, outputDir, appDirectory},
175+
{stdout: mockStdout},
176+
)
177+
178+
// Then
179+
expect(result.filesCopied).toBe(5)
180+
expect(result.outputPaths).toHaveLength(5)
181+
expect(result.outputPaths).toEqual(
182+
expect.arrayContaining(['theme/a.js', 'theme/b.js', 'theme/c.js', 'theme/d.js', 'theme/e.js']),
183+
)
184+
})
136185
})
137186

138187
test('creates parent directories before copying a file', async () => {
139-
// Given
140-
vi.mocked(fs.fileExists).mockResolvedValue(true)
141-
vi.mocked(fs.isDirectory).mockResolvedValue(false)
142-
vi.mocked(fs.mkdir).mockResolvedValue()
143-
vi.mocked(fs.copyFile).mockResolvedValue()
144-
145-
// When
146-
await copySourceEntry(
147-
{
148-
source: 'src/deep/icon.png',
149-
destination: 'assets/icons/icon.png',
150-
baseDir: '/ext',
151-
outputDir: '/out',
152-
appDirectory: '/ext',
153-
},
154-
{stdout: mockStdout},
155-
)
156-
157-
// Then — parent of destination path created
158-
expect(fs.mkdir).toHaveBeenCalledWith('/out/assets/icons')
188+
await inTemporaryDirectory(async (tmpDir) => {
189+
// Given
190+
const baseDir = joinPath(tmpDir, 'ext')
191+
const outputDir = joinPath(tmpDir, 'out')
192+
const appDirectory = tmpDir
193+
await mkdir(baseDir)
194+
await mkdir(outputDir)
195+
196+
const deepDir = joinPath(baseDir, 'src/deep')
197+
await mkdir(deepDir)
198+
await writeFile(joinPath(deepDir, 'icon.png'), 'icon')
199+
200+
// When
201+
await copySourceEntry(
202+
{
203+
source: 'src/deep/icon.png',
204+
destination: 'assets/icons/icon.png',
205+
baseDir,
206+
outputDir,
207+
appDirectory,
208+
},
209+
{stdout: mockStdout},
210+
)
211+
212+
// Then — parent of destination path created
213+
expect(fileExistsSync(joinPath(outputDir, 'assets/icons/icon.png'))).toBe(true)
214+
})
159215
})
160216
})

0 commit comments

Comments
 (0)