@cloudflare/sandbox 0.5.6 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +54 -56
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -6
- package/.turbo/turbo-build.log +0 -23
- package/CHANGELOG.md +0 -463
- package/src/clients/base-client.ts +0 -356
- package/src/clients/command-client.ts +0 -133
- package/src/clients/file-client.ts +0 -300
- package/src/clients/git-client.ts +0 -98
- package/src/clients/index.ts +0 -64
- package/src/clients/interpreter-client.ts +0 -339
- package/src/clients/port-client.ts +0 -105
- package/src/clients/process-client.ts +0 -198
- package/src/clients/sandbox-client.ts +0 -39
- package/src/clients/types.ts +0 -88
- package/src/clients/utility-client.ts +0 -156
- package/src/errors/adapter.ts +0 -238
- package/src/errors/classes.ts +0 -594
- package/src/errors/index.ts +0 -109
- package/src/file-stream.ts +0 -175
- package/src/index.ts +0 -121
- package/src/interpreter.ts +0 -168
- package/src/openai/index.ts +0 -465
- package/src/request-handler.ts +0 -184
- package/src/sandbox.ts +0 -1937
- package/src/security.ts +0 -119
- package/src/sse-parser.ts +0 -147
- package/src/storage-mount/credential-detection.ts +0 -41
- package/src/storage-mount/errors.ts +0 -51
- package/src/storage-mount/index.ts +0 -17
- package/src/storage-mount/provider-detection.ts +0 -93
- package/src/storage-mount/types.ts +0 -17
- package/src/version.ts +0 -6
- package/tests/base-client.test.ts +0 -582
- package/tests/command-client.test.ts +0 -444
- package/tests/file-client.test.ts +0 -831
- package/tests/file-stream.test.ts +0 -310
- package/tests/get-sandbox.test.ts +0 -172
- package/tests/git-client.test.ts +0 -455
- package/tests/openai-shell-editor.test.ts +0 -434
- package/tests/port-client.test.ts +0 -283
- package/tests/process-client.test.ts +0 -649
- package/tests/request-handler.test.ts +0 -292
- package/tests/sandbox.test.ts +0 -890
- package/tests/sse-parser.test.ts +0 -291
- package/tests/storage-mount/credential-detection.test.ts +0 -119
- package/tests/storage-mount/provider-detection.test.ts +0 -77
- package/tests/utility-client.test.ts +0 -339
- package/tests/version.test.ts +0 -16
- package/tests/wrangler.jsonc +0 -35
- package/tsconfig.json +0 -11
- package/tsdown.config.ts +0 -13
- package/vitest.config.ts +0 -31
package/tests/git-client.test.ts
DELETED
|
@@ -1,455 +0,0 @@
|
|
|
1
|
-
import type { GitCheckoutResult } from '@repo/shared';
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { GitClient } from '../src/clients/git-client';
|
|
4
|
-
import {
|
|
5
|
-
GitAuthenticationError,
|
|
6
|
-
GitBranchNotFoundError,
|
|
7
|
-
GitCheckoutError,
|
|
8
|
-
GitCloneError,
|
|
9
|
-
GitError,
|
|
10
|
-
GitNetworkError,
|
|
11
|
-
GitRepositoryNotFoundError,
|
|
12
|
-
InvalidGitUrlError,
|
|
13
|
-
SandboxError
|
|
14
|
-
} from '../src/errors';
|
|
15
|
-
|
|
16
|
-
describe('GitClient', () => {
|
|
17
|
-
let client: GitClient;
|
|
18
|
-
let mockFetch: ReturnType<typeof vi.fn>;
|
|
19
|
-
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
vi.clearAllMocks();
|
|
22
|
-
|
|
23
|
-
mockFetch = vi.fn();
|
|
24
|
-
global.fetch = mockFetch as unknown as typeof fetch;
|
|
25
|
-
|
|
26
|
-
client = new GitClient({
|
|
27
|
-
baseUrl: 'http://test.com',
|
|
28
|
-
port: 3000
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
vi.restoreAllMocks();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('repository cloning', () => {
|
|
37
|
-
it('should clone public repositories successfully', async () => {
|
|
38
|
-
const mockResponse: GitCheckoutResult = {
|
|
39
|
-
success: true,
|
|
40
|
-
repoUrl: 'https://github.com/facebook/react.git',
|
|
41
|
-
branch: 'main',
|
|
42
|
-
targetDir: 'react',
|
|
43
|
-
timestamp: '2023-01-01T00:00:00Z'
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
mockFetch.mockResolvedValue(
|
|
47
|
-
new Response(JSON.stringify(mockResponse), { status: 200 })
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
const result = await client.checkout(
|
|
51
|
-
'https://github.com/facebook/react.git',
|
|
52
|
-
'test-session'
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
expect(result.success).toBe(true);
|
|
56
|
-
expect(result.repoUrl).toBe('https://github.com/facebook/react.git');
|
|
57
|
-
expect(result.branch).toBe('main');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should clone repositories to specific branches', async () => {
|
|
61
|
-
const mockResponse: GitCheckoutResult = {
|
|
62
|
-
success: true,
|
|
63
|
-
repoUrl: 'https://github.com/company/project.git',
|
|
64
|
-
branch: 'development',
|
|
65
|
-
targetDir: 'project',
|
|
66
|
-
timestamp: '2023-01-01T00:00:00Z'
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
mockFetch.mockResolvedValue(
|
|
70
|
-
new Response(JSON.stringify(mockResponse), { status: 200 })
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
const result = await client.checkout(
|
|
74
|
-
'https://github.com/company/project.git',
|
|
75
|
-
'test-session',
|
|
76
|
-
{ branch: 'development' }
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
expect(result.success).toBe(true);
|
|
80
|
-
expect(result.branch).toBe('development');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should clone repositories to custom directories', async () => {
|
|
84
|
-
const mockResponse: GitCheckoutResult = {
|
|
85
|
-
success: true,
|
|
86
|
-
repoUrl: 'https://github.com/user/my-app.git',
|
|
87
|
-
branch: 'main',
|
|
88
|
-
targetDir: 'workspace/my-app',
|
|
89
|
-
timestamp: '2023-01-01T00:00:00Z'
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
mockFetch.mockResolvedValue(
|
|
93
|
-
new Response(JSON.stringify(mockResponse), { status: 200 })
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
const result = await client.checkout(
|
|
97
|
-
'https://github.com/user/my-app.git',
|
|
98
|
-
'test-session',
|
|
99
|
-
{ targetDir: 'workspace/my-app' }
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
expect(result.success).toBe(true);
|
|
103
|
-
expect(result.targetDir).toBe('workspace/my-app');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should handle large repository clones with warnings', async () => {
|
|
107
|
-
const mockResponse: GitCheckoutResult = {
|
|
108
|
-
success: true,
|
|
109
|
-
repoUrl: 'https://github.com/torvalds/linux.git',
|
|
110
|
-
branch: 'master',
|
|
111
|
-
targetDir: 'linux',
|
|
112
|
-
timestamp: '2023-01-01T00:05:30Z'
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
mockFetch.mockResolvedValue(
|
|
116
|
-
new Response(JSON.stringify(mockResponse), { status: 200 })
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const result = await client.checkout(
|
|
120
|
-
'https://github.com/torvalds/linux.git',
|
|
121
|
-
'test-session'
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
expect(result.success).toBe(true);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should handle SSH repository URLs', async () => {
|
|
128
|
-
const mockResponse: GitCheckoutResult = {
|
|
129
|
-
success: true,
|
|
130
|
-
repoUrl: 'git@github.com:company/private-project.git',
|
|
131
|
-
branch: 'main',
|
|
132
|
-
targetDir: 'private-project',
|
|
133
|
-
timestamp: '2023-01-01T00:00:00Z'
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
mockFetch.mockResolvedValue(
|
|
137
|
-
new Response(JSON.stringify(mockResponse), { status: 200 })
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
const result = await client.checkout(
|
|
141
|
-
'git@github.com:company/private-project.git',
|
|
142
|
-
'test-session'
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
expect(result.success).toBe(true);
|
|
146
|
-
expect(result.repoUrl).toBe('git@github.com:company/private-project.git');
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should handle concurrent repository operations', async () => {
|
|
150
|
-
mockFetch.mockImplementation((url: string, options: RequestInit) => {
|
|
151
|
-
const body = JSON.parse(options.body as string);
|
|
152
|
-
const repoName = body.repoUrl.split('/').pop().replace('.git', '');
|
|
153
|
-
|
|
154
|
-
return Promise.resolve(
|
|
155
|
-
new Response(
|
|
156
|
-
JSON.stringify({
|
|
157
|
-
success: true,
|
|
158
|
-
stdout: `Cloning into '${repoName}'...\nDone.`,
|
|
159
|
-
repoUrl: body.repoUrl,
|
|
160
|
-
branch: body.branch || 'main',
|
|
161
|
-
targetDir: body.targetDir || repoName,
|
|
162
|
-
timestamp: new Date().toISOString()
|
|
163
|
-
})
|
|
164
|
-
)
|
|
165
|
-
);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const operations = await Promise.all([
|
|
169
|
-
client.checkout('https://github.com/facebook/react.git', 'session-1'),
|
|
170
|
-
client.checkout('https://github.com/microsoft/vscode.git', 'session-2'),
|
|
171
|
-
client.checkout('https://github.com/nodejs/node.git', 'session-3', {
|
|
172
|
-
branch: 'v18.x'
|
|
173
|
-
})
|
|
174
|
-
]);
|
|
175
|
-
|
|
176
|
-
expect(operations).toHaveLength(3);
|
|
177
|
-
operations.forEach((result) => {
|
|
178
|
-
expect(result.success).toBe(true);
|
|
179
|
-
});
|
|
180
|
-
expect(mockFetch).toHaveBeenCalledTimes(3);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
describe('repository error handling', () => {
|
|
185
|
-
it('should handle repository not found errors', async () => {
|
|
186
|
-
mockFetch.mockResolvedValue(
|
|
187
|
-
new Response(
|
|
188
|
-
JSON.stringify({
|
|
189
|
-
error: 'Repository not found',
|
|
190
|
-
code: 'GIT_REPOSITORY_NOT_FOUND'
|
|
191
|
-
}),
|
|
192
|
-
{ status: 404 }
|
|
193
|
-
)
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
await expect(
|
|
197
|
-
client.checkout(
|
|
198
|
-
'https://github.com/user/nonexistent.git',
|
|
199
|
-
'test-session'
|
|
200
|
-
)
|
|
201
|
-
).rejects.toThrow(GitRepositoryNotFoundError);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('should handle authentication failures', async () => {
|
|
205
|
-
mockFetch.mockResolvedValue(
|
|
206
|
-
new Response(
|
|
207
|
-
JSON.stringify({
|
|
208
|
-
error: 'Authentication failed',
|
|
209
|
-
code: 'GIT_AUTH_FAILED'
|
|
210
|
-
}),
|
|
211
|
-
{ status: 401 }
|
|
212
|
-
)
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
await expect(
|
|
216
|
-
client.checkout(
|
|
217
|
-
'https://github.com/company/private.git',
|
|
218
|
-
'test-session'
|
|
219
|
-
)
|
|
220
|
-
).rejects.toThrow(GitAuthenticationError);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it('should handle branch not found errors', async () => {
|
|
224
|
-
mockFetch.mockResolvedValue(
|
|
225
|
-
new Response(
|
|
226
|
-
JSON.stringify({
|
|
227
|
-
error: 'Branch not found',
|
|
228
|
-
code: 'GIT_BRANCH_NOT_FOUND'
|
|
229
|
-
}),
|
|
230
|
-
{ status: 404 }
|
|
231
|
-
)
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
await expect(
|
|
235
|
-
client.checkout('https://github.com/user/repo.git', 'test-session', {
|
|
236
|
-
branch: 'nonexistent-branch'
|
|
237
|
-
})
|
|
238
|
-
).rejects.toThrow(GitBranchNotFoundError);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('should handle network errors', async () => {
|
|
242
|
-
mockFetch.mockResolvedValue(
|
|
243
|
-
new Response(
|
|
244
|
-
JSON.stringify({ error: 'Network error', code: 'GIT_NETWORK_ERROR' }),
|
|
245
|
-
{ status: 503 }
|
|
246
|
-
)
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
await expect(
|
|
250
|
-
client.checkout('https://github.com/user/repo.git', 'test-session')
|
|
251
|
-
).rejects.toThrow(GitNetworkError);
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it('should handle clone failures', async () => {
|
|
255
|
-
mockFetch.mockResolvedValue(
|
|
256
|
-
new Response(
|
|
257
|
-
JSON.stringify({ error: 'Clone failed', code: 'GIT_CLONE_FAILED' }),
|
|
258
|
-
{ status: 507 }
|
|
259
|
-
)
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
await expect(
|
|
263
|
-
client.checkout(
|
|
264
|
-
'https://github.com/large/repository.git',
|
|
265
|
-
'test-session'
|
|
266
|
-
)
|
|
267
|
-
).rejects.toThrow(GitCloneError);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it('should handle checkout failures', async () => {
|
|
271
|
-
mockFetch.mockResolvedValue(
|
|
272
|
-
new Response(
|
|
273
|
-
JSON.stringify({
|
|
274
|
-
error: 'Checkout failed',
|
|
275
|
-
code: 'GIT_CHECKOUT_FAILED'
|
|
276
|
-
}),
|
|
277
|
-
{ status: 409 }
|
|
278
|
-
)
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
await expect(
|
|
282
|
-
client.checkout('https://github.com/user/repo.git', 'test-session', {
|
|
283
|
-
branch: 'feature-branch'
|
|
284
|
-
})
|
|
285
|
-
).rejects.toThrow(GitCheckoutError);
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
it('should handle invalid Git URLs', async () => {
|
|
289
|
-
mockFetch.mockResolvedValue(
|
|
290
|
-
new Response(
|
|
291
|
-
JSON.stringify({ error: 'Invalid Git URL', code: 'INVALID_GIT_URL' }),
|
|
292
|
-
{ status: 400 }
|
|
293
|
-
)
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
await expect(
|
|
297
|
-
client.checkout('not-a-valid-url', 'test-session')
|
|
298
|
-
).rejects.toThrow(InvalidGitUrlError);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should handle partial clone failures', async () => {
|
|
302
|
-
const mockResponse: GitCheckoutResult = {
|
|
303
|
-
success: false,
|
|
304
|
-
repoUrl: 'https://github.com/problematic/repo.git',
|
|
305
|
-
branch: 'main',
|
|
306
|
-
targetDir: 'repo',
|
|
307
|
-
timestamp: '2023-01-01T00:01:30Z'
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
mockFetch.mockResolvedValue(
|
|
311
|
-
new Response(JSON.stringify(mockResponse), { status: 200 })
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
const result = await client.checkout(
|
|
315
|
-
'https://github.com/problematic/repo.git',
|
|
316
|
-
'test-session'
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
expect(result.success).toBe(false);
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
describe('error handling edge cases', () => {
|
|
324
|
-
it('should handle network failures', async () => {
|
|
325
|
-
mockFetch.mockRejectedValue(new Error('Network connection failed'));
|
|
326
|
-
|
|
327
|
-
await expect(
|
|
328
|
-
client.checkout('https://github.com/user/repo.git', 'test-session')
|
|
329
|
-
).rejects.toThrow('Network connection failed');
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
it('should handle malformed server responses', async () => {
|
|
333
|
-
mockFetch.mockResolvedValue(
|
|
334
|
-
new Response('invalid json {', { status: 200 })
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
await expect(
|
|
338
|
-
client.checkout('https://github.com/user/repo.git', 'test-session')
|
|
339
|
-
).rejects.toThrow(SandboxError);
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it('should map server errors to client errors', async () => {
|
|
343
|
-
const serverErrorScenarios = [
|
|
344
|
-
{ status: 400, code: 'INVALID_GIT_URL', error: InvalidGitUrlError },
|
|
345
|
-
{ status: 401, code: 'GIT_AUTH_FAILED', error: GitAuthenticationError },
|
|
346
|
-
{
|
|
347
|
-
status: 404,
|
|
348
|
-
code: 'GIT_REPOSITORY_NOT_FOUND',
|
|
349
|
-
error: GitRepositoryNotFoundError
|
|
350
|
-
},
|
|
351
|
-
{
|
|
352
|
-
status: 404,
|
|
353
|
-
code: 'GIT_BRANCH_NOT_FOUND',
|
|
354
|
-
error: GitBranchNotFoundError
|
|
355
|
-
},
|
|
356
|
-
{ status: 500, code: 'GIT_OPERATION_FAILED', error: GitError },
|
|
357
|
-
{ status: 503, code: 'GIT_NETWORK_ERROR', error: GitNetworkError }
|
|
358
|
-
];
|
|
359
|
-
|
|
360
|
-
for (const scenario of serverErrorScenarios) {
|
|
361
|
-
mockFetch.mockResolvedValueOnce(
|
|
362
|
-
new Response(
|
|
363
|
-
JSON.stringify({ error: 'Test error', code: scenario.code }),
|
|
364
|
-
{ status: scenario.status }
|
|
365
|
-
)
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
await expect(
|
|
369
|
-
client.checkout('https://github.com/test/repo.git', 'test-session')
|
|
370
|
-
).rejects.toThrow(scenario.error);
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
describe('constructor options', () => {
|
|
376
|
-
it('should initialize with minimal options', () => {
|
|
377
|
-
const minimalClient = new GitClient();
|
|
378
|
-
expect(minimalClient).toBeInstanceOf(GitClient);
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
it('should initialize with full options', () => {
|
|
382
|
-
const fullOptionsClient = new GitClient({
|
|
383
|
-
baseUrl: 'http://custom.com',
|
|
384
|
-
port: 8080
|
|
385
|
-
});
|
|
386
|
-
expect(fullOptionsClient).toBeInstanceOf(GitClient);
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
describe('credential redaction in logs', () => {
|
|
391
|
-
it('should redact credentials from URLs but leave public URLs unchanged', async () => {
|
|
392
|
-
const mockLogger = {
|
|
393
|
-
info: vi.fn(),
|
|
394
|
-
warn: vi.fn(),
|
|
395
|
-
error: vi.fn(),
|
|
396
|
-
debug: vi.fn(),
|
|
397
|
-
child: vi.fn()
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
const clientWithLogger = new GitClient({
|
|
401
|
-
baseUrl: 'http://test.com',
|
|
402
|
-
port: 3000,
|
|
403
|
-
logger: mockLogger
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
// Test with credentials
|
|
407
|
-
mockFetch.mockResolvedValueOnce(
|
|
408
|
-
new Response(
|
|
409
|
-
JSON.stringify({
|
|
410
|
-
success: true,
|
|
411
|
-
repoUrl:
|
|
412
|
-
'https://oauth2:ghp_token123@github.com/user/private-repo.git',
|
|
413
|
-
branch: 'main',
|
|
414
|
-
targetDir: '/workspace/private-repo',
|
|
415
|
-
timestamp: '2023-01-01T00:00:00Z'
|
|
416
|
-
}),
|
|
417
|
-
{ status: 200 }
|
|
418
|
-
)
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
await clientWithLogger.checkout(
|
|
422
|
-
'https://oauth2:ghp_token123@github.com/user/private-repo.git',
|
|
423
|
-
'test-session'
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
let logDetails = mockLogger.info.mock.calls[0]?.[1]?.details;
|
|
427
|
-
expect(logDetails).not.toContain('ghp_token123');
|
|
428
|
-
expect(logDetails).toContain(
|
|
429
|
-
'https://******@github.com/user/private-repo.git'
|
|
430
|
-
);
|
|
431
|
-
|
|
432
|
-
// Test without credentials
|
|
433
|
-
mockFetch.mockResolvedValueOnce(
|
|
434
|
-
new Response(
|
|
435
|
-
JSON.stringify({
|
|
436
|
-
success: true,
|
|
437
|
-
repoUrl: 'https://github.com/facebook/react.git',
|
|
438
|
-
branch: 'main',
|
|
439
|
-
targetDir: '/workspace/react',
|
|
440
|
-
timestamp: '2023-01-01T00:00:00Z'
|
|
441
|
-
}),
|
|
442
|
-
{ status: 200 }
|
|
443
|
-
)
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
await clientWithLogger.checkout(
|
|
447
|
-
'https://github.com/facebook/react.git',
|
|
448
|
-
'test-session'
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
logDetails = mockLogger.info.mock.calls[1]?.[1]?.details;
|
|
452
|
-
expect(logDetails).toContain('https://github.com/facebook/react.git');
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
});
|