@sanity/cli 6.0.0-alpha.3 → 6.0.0-alpha.4
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/dist/actions/auth/login/{index.js → login.js} +1 -1
- package/dist/actions/auth/login/{index.js.map → login.js.map} +1 -1
- package/dist/actions/organizations/getOrganizationChoices.d.ts +6 -0
- package/dist/actions/organizations/getOrganizationChoices.js +23 -0
- package/dist/actions/organizations/getOrganizationChoices.js.map +1 -0
- package/dist/actions/organizations/getOrganizationsWithAttachGrantInfo.d.ts +2 -0
- package/dist/actions/organizations/getOrganizationsWithAttachGrantInfo.js +9 -0
- package/dist/actions/organizations/getOrganizationsWithAttachGrantInfo.js.map +1 -0
- package/dist/actions/organizations/hasProjectAttachGrant.d.ts +1 -0
- package/dist/actions/organizations/hasProjectAttachGrant.js +24 -0
- package/dist/actions/organizations/hasProjectAttachGrant.js.map +1 -0
- package/dist/actions/schema/utils/schemaStoreValidation.js +2 -2
- package/dist/actions/schema/utils/schemaStoreValidation.js.map +1 -1
- package/dist/commands/__tests__/init/init.authentication.test.js +60 -0
- package/dist/commands/__tests__/init/init.authentication.test.js.map +1 -0
- package/dist/commands/__tests__/init/init.create-new-project.test.js +196 -0
- package/dist/commands/__tests__/init/init.create-new-project.test.js.map +1 -0
- package/dist/commands/__tests__/init/init.plan.test.js +220 -0
- package/dist/commands/__tests__/init/init.plan.test.js.map +1 -0
- package/dist/commands/__tests__/init/init.setup.test.js +279 -0
- package/dist/commands/__tests__/init/init.setup.test.js.map +1 -0
- package/dist/commands/__tests__/migration.test.js +119 -0
- package/dist/commands/__tests__/migration.test.js.map +1 -0
- package/dist/commands/backup/__tests__/download.test.js +3 -3
- package/dist/commands/backup/__tests__/download.test.js.map +1 -1
- package/dist/commands/dataset/__tests__/import.test.js +2 -2
- package/dist/commands/dataset/__tests__/import.test.js.map +1 -1
- package/dist/commands/documents/__tests__/query.test.js +3 -3
- package/dist/commands/documents/__tests__/query.test.js.map +1 -1
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +151 -18
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/services/organizations.d.ts +40 -0
- package/dist/services/organizations.js +41 -0
- package/dist/services/organizations.js.map +1 -0
- package/dist/services/projects.d.ts +20 -0
- package/dist/services/projects.js +30 -1
- package/dist/services/projects.js.map +1 -1
- package/dist/services/user.d.ts +2 -0
- package/dist/services/user.js +11 -0
- package/dist/services/user.js.map +1 -0
- package/oclif.config.js +6 -1
- package/oclif.manifest.json +33 -184
- package/package.json +7 -7
- package/dist/actions/migration/getMigrationRootDirectory.d.ts +0 -2
- package/dist/actions/migration/getMigrationRootDirectory.js +0 -14
- package/dist/actions/migration/getMigrationRootDirectory.js.map +0 -1
- package/dist/actions/migration/resolveMigrations.d.ts +0 -19
- package/dist/actions/migration/resolveMigrations.js +0 -43
- package/dist/actions/migration/resolveMigrations.js.map +0 -1
- package/dist/actions/migration/templates/__tests__/minimalAdvanced.test.js +0 -65
- package/dist/actions/migration/templates/__tests__/minimalAdvanced.test.js.map +0 -1
- package/dist/actions/migration/templates/__tests__/minimalSimple.test.js +0 -145
- package/dist/actions/migration/templates/__tests__/minimalSimple.test.js.map +0 -1
- package/dist/actions/migration/templates/__tests__/renameField.test.js +0 -63
- package/dist/actions/migration/templates/__tests__/renameField.test.js.map +0 -1
- package/dist/actions/migration/templates/__tests__/renameType.test.js +0 -61
- package/dist/actions/migration/templates/__tests__/renameType.test.js.map +0 -1
- package/dist/actions/migration/templates/__tests__/stringToPTE.test.js +0 -87
- package/dist/actions/migration/templates/__tests__/stringToPTE.test.js.map +0 -1
- package/dist/actions/migration/templates/index.d.ts +0 -5
- package/dist/actions/migration/templates/index.js +0 -7
- package/dist/actions/migration/templates/index.js.map +0 -1
- package/dist/actions/migration/templates/minimalAdvanced.d.ts +0 -4
- package/dist/actions/migration/templates/minimalAdvanced.js +0 -21
- package/dist/actions/migration/templates/minimalAdvanced.js.map +0 -1
- package/dist/actions/migration/templates/minimalSimple.d.ts +0 -4
- package/dist/actions/migration/templates/minimalSimple.js +0 -61
- package/dist/actions/migration/templates/minimalSimple.js.map +0 -1
- package/dist/actions/migration/templates/renameField.d.ts +0 -4
- package/dist/actions/migration/templates/renameField.js +0 -20
- package/dist/actions/migration/templates/renameField.js.map +0 -1
- package/dist/actions/migration/templates/renameType.d.ts +0 -4
- package/dist/actions/migration/templates/renameType.js +0 -19
- package/dist/actions/migration/templates/renameType.js.map +0 -1
- package/dist/actions/migration/templates/stringToPTE.d.ts +0 -4
- package/dist/actions/migration/templates/stringToPTE.js +0 -32
- package/dist/actions/migration/templates/stringToPTE.js.map +0 -1
- package/dist/commands/__tests__/init.test.js +0 -411
- package/dist/commands/__tests__/init.test.js.map +0 -1
- package/dist/commands/migration/__tests__/create.test.js +0 -296
- package/dist/commands/migration/__tests__/create.test.js.map +0 -1
- package/dist/commands/migration/__tests__/list.test.js +0 -166
- package/dist/commands/migration/__tests__/list.test.js.map +0 -1
- package/dist/commands/migration/__tests__/run.test.js +0 -481
- package/dist/commands/migration/__tests__/run.test.js.map +0 -1
- package/dist/commands/migration/create.d.ts +0 -17
- package/dist/commands/migration/create.js +0 -143
- package/dist/commands/migration/create.js.map +0 -1
- package/dist/commands/migration/list.d.ts +0 -9
- package/dist/commands/migration/list.js +0 -61
- package/dist/commands/migration/list.js.map +0 -1
- package/dist/commands/migration/run.d.ts +0 -26
- package/dist/commands/migration/run.js +0 -271
- package/dist/commands/migration/run.js.map +0 -1
- package/dist/util/migration/constants.d.ts +0 -3
- package/dist/util/migration/constants.js +0 -10
- package/dist/util/migration/constants.js.map +0 -1
- package/dist/util/migration/ensureApiVersionFormat.d.ts +0 -9
- package/dist/util/migration/ensureApiVersionFormat.js +0 -16
- package/dist/util/migration/ensureApiVersionFormat.js.map +0 -1
- package/dist/util/migration/prettyMutationFormatter.d.ts +0 -8
- package/dist/util/migration/prettyMutationFormatter.js +0 -141
- package/dist/util/migration/prettyMutationFormatter.js.map +0 -1
- package/dist/utils/migration/resolveMigrationScript.d.ts +0 -44
- package/dist/utils/migration/resolveMigrationScript.js +0 -74
- package/dist/utils/migration/resolveMigrationScript.js.map +0 -1
- /package/dist/actions/auth/login/{index.d.ts → login.d.ts} +0 -0
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
import { access, mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { runCommand } from '@oclif/test';
|
|
3
|
-
import { testCommand } from '@sanity/cli-test';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
5
|
-
import { CreateMigrationCommand } from '../create.js';
|
|
6
|
-
const mocks = vi.hoisted(()=>({
|
|
7
|
-
confirm: vi.fn(),
|
|
8
|
-
findProjectRoot: vi.fn(),
|
|
9
|
-
input: vi.fn(),
|
|
10
|
-
select: vi.fn()
|
|
11
|
-
}));
|
|
12
|
-
const mockTemplates = vi.hoisted(()=>({
|
|
13
|
-
minimalAdvanced: vi.fn(),
|
|
14
|
-
minimalSimple: vi.fn(),
|
|
15
|
-
renameField: vi.fn(),
|
|
16
|
-
renameType: vi.fn(),
|
|
17
|
-
stringToPTE: vi.fn()
|
|
18
|
-
}));
|
|
19
|
-
vi.mock('node:fs');
|
|
20
|
-
vi.mock('node:fs/promises', ()=>({
|
|
21
|
-
access: vi.fn(),
|
|
22
|
-
mkdir: vi.fn(),
|
|
23
|
-
writeFile: vi.fn()
|
|
24
|
-
}));
|
|
25
|
-
vi.mock('@sanity/cli-core/ux', async ()=>{
|
|
26
|
-
const actual = await vi.importActual('@sanity/cli-core/ux');
|
|
27
|
-
return {
|
|
28
|
-
...actual,
|
|
29
|
-
confirm: mocks.confirm,
|
|
30
|
-
input: mocks.input,
|
|
31
|
-
select: mocks.select
|
|
32
|
-
};
|
|
33
|
-
});
|
|
34
|
-
vi.mock('../../../../../cli-core/src/config/findProjectRoot.js', ()=>({
|
|
35
|
-
findProjectRoot: mocks.findProjectRoot
|
|
36
|
-
}));
|
|
37
|
-
vi.mock('../../../actions/migration/templates/index.js', ()=>mockTemplates);
|
|
38
|
-
const mockConfirm = mocks.confirm;
|
|
39
|
-
const mockFindProjectRoot = mocks.findProjectRoot;
|
|
40
|
-
const mockInput = mocks.input;
|
|
41
|
-
const mockSelect = mocks.select;
|
|
42
|
-
const mockAccess = vi.mocked(access);
|
|
43
|
-
const mockMkdir = vi.mocked(mkdir);
|
|
44
|
-
const mockWriteFile = vi.mocked(writeFile);
|
|
45
|
-
describe('#migration:create', ()=>{
|
|
46
|
-
beforeEach(()=>{
|
|
47
|
-
mockFindProjectRoot.mockResolvedValue({
|
|
48
|
-
directory: '/test/path',
|
|
49
|
-
root: '/test/path',
|
|
50
|
-
type: 'studio'
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
afterEach(()=>{
|
|
54
|
-
vi.clearAllMocks();
|
|
55
|
-
});
|
|
56
|
-
test('--help works', async ()=>{
|
|
57
|
-
const { stdout } = await runCommand([
|
|
58
|
-
'migration create',
|
|
59
|
-
'--help'
|
|
60
|
-
]);
|
|
61
|
-
expect(stdout).toMatchInlineSnapshot(`
|
|
62
|
-
"Create a new migration within your project
|
|
63
|
-
|
|
64
|
-
USAGE
|
|
65
|
-
$ sanity migration create [TITLE]
|
|
66
|
-
|
|
67
|
-
ARGUMENTS
|
|
68
|
-
[TITLE] Title of migration
|
|
69
|
-
|
|
70
|
-
DESCRIPTION
|
|
71
|
-
Create a new migration within your project
|
|
72
|
-
|
|
73
|
-
EXAMPLES
|
|
74
|
-
Create a new migration, prompting for title and options
|
|
75
|
-
|
|
76
|
-
$ sanity migration create
|
|
77
|
-
|
|
78
|
-
Create a new migration with the provided title, prompting for options
|
|
79
|
-
|
|
80
|
-
$ sanity migration create "Rename field from location to address"
|
|
81
|
-
|
|
82
|
-
"
|
|
83
|
-
`);
|
|
84
|
-
});
|
|
85
|
-
test('prompts user to enter title when no title argument is provided', async ()=>{
|
|
86
|
-
await testCommand(CreateMigrationCommand);
|
|
87
|
-
expect(mockInput).toHaveBeenCalledWith({
|
|
88
|
-
message: 'Title of migration (e.g. "Rename field from location to address")',
|
|
89
|
-
validate: expect.any(Function)
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
test('skips title prompt when title is provided', async ()=>{
|
|
93
|
-
await testCommand(CreateMigrationCommand, [
|
|
94
|
-
'Migration Title'
|
|
95
|
-
]);
|
|
96
|
-
expect(mockInput).toHaveBeenCalledWith({
|
|
97
|
-
message: 'Type of documents to migrate. You can add multiple types separated by comma (optional)'
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
test('errors gracefully if findProjectRoot fails', async ()=>{
|
|
101
|
-
mockFindProjectRoot.mockRejectedValue(new Error('No project root found'));
|
|
102
|
-
const { error } = await testCommand(CreateMigrationCommand, [
|
|
103
|
-
'Migration Title'
|
|
104
|
-
]);
|
|
105
|
-
expect(error?.message).toContain('No project root found');
|
|
106
|
-
});
|
|
107
|
-
test('prompts user for type of documents for migration after a valid migration name has been entered', async ()=>{
|
|
108
|
-
mockInput.mockResolvedValueOnce('Migration Title');
|
|
109
|
-
await testCommand(CreateMigrationCommand);
|
|
110
|
-
expect(mockInput.mock.calls[1][0]).toStrictEqual({
|
|
111
|
-
message: 'Type of documents to migrate. You can add multiple types separated by comma (optional)'
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
test('prompts user for template selection after migration name and optional document types', async ()=>{
|
|
115
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
116
|
-
await testCommand(CreateMigrationCommand, [
|
|
117
|
-
'Migration Title'
|
|
118
|
-
]);
|
|
119
|
-
expect(mockSelect).toHaveBeenCalledWith({
|
|
120
|
-
choices: [
|
|
121
|
-
{
|
|
122
|
-
name: 'Minimalistic migration to get you started',
|
|
123
|
-
value: 'Minimalistic migration to get you started'
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: 'Rename an object type',
|
|
127
|
-
value: 'Rename an object type'
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
name: 'Rename a field',
|
|
131
|
-
value: 'Rename a field'
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
name: 'Convert string field to Portable Text',
|
|
135
|
-
value: 'Convert string field to Portable Text'
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: 'Advanced template using async iterators providing more fine grained control',
|
|
139
|
-
value: 'Advanced template using async iterators providing more fine grained control'
|
|
140
|
-
}
|
|
141
|
-
],
|
|
142
|
-
message: 'Select a template'
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
test('creates directory when it does not exist', async ()=>{
|
|
146
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
147
|
-
mockSelect.mockResolvedValue('Rename a field');
|
|
148
|
-
mockAccess.mockRejectedValue(new Error('ENOENT: no such file or directory'));
|
|
149
|
-
await testCommand(CreateMigrationCommand, [
|
|
150
|
-
'Migration Title'
|
|
151
|
-
]);
|
|
152
|
-
expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('/test/path/migrations/migration-title'), {
|
|
153
|
-
recursive: true
|
|
154
|
-
});
|
|
155
|
-
expect(mockConfirm).not.toHaveBeenCalled();
|
|
156
|
-
});
|
|
157
|
-
test('prompts the user to overwrite when directory already exists', async ()=>{
|
|
158
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
159
|
-
mockSelect.mockResolvedValue('Rename a field');
|
|
160
|
-
mockAccess.mockResolvedValue();
|
|
161
|
-
mockConfirm.mockResolvedValue(true);
|
|
162
|
-
await testCommand(CreateMigrationCommand, [
|
|
163
|
-
'My Migration'
|
|
164
|
-
]);
|
|
165
|
-
expect(mockConfirm).toHaveBeenCalledWith({
|
|
166
|
-
default: false,
|
|
167
|
-
message: expect.stringContaining('Migration directory /test/path/migrations/my-migration already exists. Overwrite?')
|
|
168
|
-
});
|
|
169
|
-
expect(mockMkdir).toHaveBeenCalled();
|
|
170
|
-
});
|
|
171
|
-
test('does not create directory when user declines overwrite', async ()=>{
|
|
172
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
173
|
-
mockSelect.mockResolvedValue('Rename a field');
|
|
174
|
-
mockAccess.mockResolvedValue();
|
|
175
|
-
mockConfirm.mockResolvedValue(false);
|
|
176
|
-
await testCommand(CreateMigrationCommand, [
|
|
177
|
-
'My Migration'
|
|
178
|
-
]);
|
|
179
|
-
expect(mockConfirm).toHaveBeenCalled();
|
|
180
|
-
expect(mockMkdir).not.toHaveBeenCalled();
|
|
181
|
-
});
|
|
182
|
-
test('creates directory after user confirms overwrite', async ()=>{
|
|
183
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
184
|
-
mockSelect.mockResolvedValue('Rename a field');
|
|
185
|
-
mockAccess.mockResolvedValue();
|
|
186
|
-
mockConfirm.mockResolvedValue(true);
|
|
187
|
-
await testCommand(CreateMigrationCommand, [
|
|
188
|
-
'My Migration'
|
|
189
|
-
]);
|
|
190
|
-
expect(mockConfirm).toHaveBeenCalled();
|
|
191
|
-
expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('test/path/migrations/my-migration'), {
|
|
192
|
-
recursive: true
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
test('exits gracefully when directory creation fails', async ()=>{
|
|
196
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
197
|
-
mockSelect.mockResolvedValue('Rename a field');
|
|
198
|
-
mockAccess.mockResolvedValue();
|
|
199
|
-
mockMkdir.mockRejectedValue(new Error('Permission denied'));
|
|
200
|
-
const { error } = await testCommand(CreateMigrationCommand, [
|
|
201
|
-
'My Migration'
|
|
202
|
-
]);
|
|
203
|
-
expect(error).toBeDefined();
|
|
204
|
-
expect(error?.message).toContain('Failed to create migration directory: Permission denied');
|
|
205
|
-
expect(mockWriteFile).not.toHaveBeenCalled();
|
|
206
|
-
});
|
|
207
|
-
test('output migration instructions after migrations folder has been created', async ()=>{
|
|
208
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
209
|
-
mockSelect.mockResolvedValue('Rename a field');
|
|
210
|
-
mockAccess.mockResolvedValue();
|
|
211
|
-
mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
|
|
212
|
-
const { stdout } = await testCommand(CreateMigrationCommand, [
|
|
213
|
-
'My Migration'
|
|
214
|
-
]);
|
|
215
|
-
expect(mockWriteFile).toHaveBeenCalled();
|
|
216
|
-
expect(stdout).toMatchInlineSnapshot(`
|
|
217
|
-
"
|
|
218
|
-
✓ Migration created!
|
|
219
|
-
|
|
220
|
-
Next steps:
|
|
221
|
-
Open /test/path/migrations/my-migration/index.ts in your code editor and write the code for your migration.
|
|
222
|
-
Dry run the migration with:
|
|
223
|
-
\`sanity migration run my-migration --project=<projectId> --dataset <dataset> \`
|
|
224
|
-
Run the migration against a dataset with:
|
|
225
|
-
\`sanity migration run my-migration --project=<projectId> --dataset <dataset> --no-dry-run\`
|
|
226
|
-
|
|
227
|
-
👉 Learn more about schema and content migrations at https://www.sanity.io/docs/schema-and-content-migrations
|
|
228
|
-
"
|
|
229
|
-
`);
|
|
230
|
-
});
|
|
231
|
-
test('creates minimalSimple template in migration folder when user selects it', async ()=>{
|
|
232
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
233
|
-
mockSelect.mockResolvedValue('Minimalistic migration to get you started');
|
|
234
|
-
mockAccess.mockResolvedValue();
|
|
235
|
-
mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
|
|
236
|
-
await testCommand(CreateMigrationCommand, [
|
|
237
|
-
'My Migration'
|
|
238
|
-
]);
|
|
239
|
-
expect(mockTemplates.minimalSimple).toHaveBeenCalled();
|
|
240
|
-
});
|
|
241
|
-
test('creates renameType template in migration folder when user selects it', async ()=>{
|
|
242
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
243
|
-
mockSelect.mockResolvedValue('Rename an object type');
|
|
244
|
-
mockAccess.mockResolvedValue();
|
|
245
|
-
mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
|
|
246
|
-
await testCommand(CreateMigrationCommand, [
|
|
247
|
-
'My Migration'
|
|
248
|
-
]);
|
|
249
|
-
expect(mockTemplates.renameType).toHaveBeenCalled();
|
|
250
|
-
});
|
|
251
|
-
test('creates renameField template in migration folder when user selects it', async ()=>{
|
|
252
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
253
|
-
mockSelect.mockResolvedValue('Rename a field');
|
|
254
|
-
mockAccess.mockResolvedValue();
|
|
255
|
-
mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
|
|
256
|
-
await testCommand(CreateMigrationCommand, [
|
|
257
|
-
'My Migration'
|
|
258
|
-
]);
|
|
259
|
-
expect(mockTemplates.renameField).toHaveBeenCalled();
|
|
260
|
-
});
|
|
261
|
-
test('creates stringToPTE template in migration folder when user selects it', async ()=>{
|
|
262
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
263
|
-
mockSelect.mockResolvedValue('Convert string field to Portable Text');
|
|
264
|
-
mockAccess.mockResolvedValue();
|
|
265
|
-
mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
|
|
266
|
-
await testCommand(CreateMigrationCommand, [
|
|
267
|
-
'My Migration'
|
|
268
|
-
]);
|
|
269
|
-
expect(mockTemplates.stringToPTE).toHaveBeenCalled();
|
|
270
|
-
});
|
|
271
|
-
test('creates minimalAdvanced template in migration folder when user selects it', async ()=>{
|
|
272
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
273
|
-
mockSelect.mockResolvedValue('Advanced template using async iterators providing more fine grained control');
|
|
274
|
-
mockAccess.mockResolvedValue();
|
|
275
|
-
mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
|
|
276
|
-
await testCommand(CreateMigrationCommand, [
|
|
277
|
-
'My Migration'
|
|
278
|
-
]);
|
|
279
|
-
expect(mockTemplates.minimalAdvanced).toHaveBeenCalled();
|
|
280
|
-
});
|
|
281
|
-
test('exits gracefully when writing the template to the directory fails', async ()=>{
|
|
282
|
-
mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
|
|
283
|
-
mockSelect.mockResolvedValue('Advanced template using async iterators providing more fine grained control');
|
|
284
|
-
mockAccess.mockResolvedValue();
|
|
285
|
-
mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
|
|
286
|
-
mockWriteFile.mockRejectedValue(new Error('Permission denied'));
|
|
287
|
-
const { error, stdout } = await testCommand(CreateMigrationCommand, [
|
|
288
|
-
'My Migration'
|
|
289
|
-
]);
|
|
290
|
-
expect(error).toBeDefined();
|
|
291
|
-
expect(error?.message).toContain('Failed to create migration file: Permission denied');
|
|
292
|
-
expect(stdout).toBe('');
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
//# sourceMappingURL=create.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/commands/migration/__tests__/create.test.ts"],"sourcesContent":["import {access, mkdir, writeFile} from 'node:fs/promises'\n\nimport {runCommand} from '@oclif/test'\nimport {testCommand} from '@sanity/cli-test'\nimport {afterEach, beforeEach, describe, expect, test, vi} from 'vitest'\n\nimport {CreateMigrationCommand} from '../create.js'\n\nconst mocks = vi.hoisted(() => ({\n confirm: vi.fn(),\n findProjectRoot: vi.fn(),\n input: vi.fn(),\n select: vi.fn(),\n}))\n\nconst mockTemplates = vi.hoisted(() => ({\n minimalAdvanced: vi.fn(),\n minimalSimple: vi.fn(),\n renameField: vi.fn(),\n renameType: vi.fn(),\n stringToPTE: vi.fn(),\n}))\n\nvi.mock('node:fs')\n\nvi.mock('node:fs/promises', () => ({\n access: vi.fn(),\n mkdir: vi.fn(),\n writeFile: vi.fn(),\n}))\n\nvi.mock('@sanity/cli-core/ux', async () => {\n const actual = await vi.importActual<typeof import('@sanity/cli-core/ux')>('@sanity/cli-core/ux')\n return {\n ...actual,\n confirm: mocks.confirm,\n input: mocks.input,\n select: mocks.select,\n }\n})\n\nvi.mock('../../../../../cli-core/src/config/findProjectRoot.js', () => ({\n findProjectRoot: mocks.findProjectRoot,\n}))\n\nvi.mock('../../../actions/migration/templates/index.js', () => mockTemplates)\n\nconst mockConfirm = mocks.confirm\nconst mockFindProjectRoot = mocks.findProjectRoot\nconst mockInput = mocks.input\nconst mockSelect = mocks.select\nconst mockAccess = vi.mocked(access)\nconst mockMkdir = vi.mocked(mkdir)\nconst mockWriteFile = vi.mocked(writeFile)\n\ndescribe('#migration:create', () => {\n beforeEach(() => {\n mockFindProjectRoot.mockResolvedValue({\n directory: '/test/path',\n root: '/test/path',\n type: 'studio',\n })\n })\n afterEach(() => {\n vi.clearAllMocks()\n })\n\n test('--help works', async () => {\n const {stdout} = await runCommand(['migration create', '--help'])\n\n expect(stdout).toMatchInlineSnapshot(`\n \"Create a new migration within your project\n\n USAGE\n $ sanity migration create [TITLE]\n\n ARGUMENTS\n [TITLE] Title of migration\n\n DESCRIPTION\n Create a new migration within your project\n\n EXAMPLES\n Create a new migration, prompting for title and options\n\n $ sanity migration create\n\n Create a new migration with the provided title, prompting for options\n\n $ sanity migration create \"Rename field from location to address\"\n\n \"\n `)\n })\n\n test('prompts user to enter title when no title argument is provided', async () => {\n await testCommand(CreateMigrationCommand)\n\n expect(mockInput).toHaveBeenCalledWith({\n message: 'Title of migration (e.g. \"Rename field from location to address\")',\n validate: expect.any(Function),\n })\n })\n\n test('skips title prompt when title is provided', async () => {\n await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(mockInput).toHaveBeenCalledWith({\n message:\n 'Type of documents to migrate. You can add multiple types separated by comma (optional)',\n })\n })\n\n test('errors gracefully if findProjectRoot fails', async () => {\n mockFindProjectRoot.mockRejectedValue(new Error('No project root found'))\n\n const {error} = await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(error?.message).toContain('No project root found')\n })\n\n test('prompts user for type of documents for migration after a valid migration name has been entered', async () => {\n mockInput.mockResolvedValueOnce('Migration Title')\n\n await testCommand(CreateMigrationCommand)\n\n expect(mockInput.mock.calls[1][0]).toStrictEqual({\n message:\n 'Type of documents to migrate. You can add multiple types separated by comma (optional)',\n })\n })\n\n test('prompts user for template selection after migration name and optional document types', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n\n await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(mockSelect).toHaveBeenCalledWith({\n choices: [\n {\n name: 'Minimalistic migration to get you started',\n value: 'Minimalistic migration to get you started',\n },\n {\n name: 'Rename an object type',\n value: 'Rename an object type',\n },\n {\n name: 'Rename a field',\n value: 'Rename a field',\n },\n {\n name: 'Convert string field to Portable Text',\n value: 'Convert string field to Portable Text',\n },\n {\n name: 'Advanced template using async iterators providing more fine grained control',\n value: 'Advanced template using async iterators providing more fine grained control',\n },\n ],\n message: 'Select a template',\n })\n })\n\n test('creates directory when it does not exist', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockRejectedValue(new Error('ENOENT: no such file or directory'))\n\n await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(mockMkdir).toHaveBeenCalledWith(\n expect.stringContaining('/test/path/migrations/migration-title'),\n {\n recursive: true,\n },\n )\n expect(mockConfirm).not.toHaveBeenCalled()\n })\n\n test('prompts the user to overwrite when directory already exists', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockConfirm.mockResolvedValue(true)\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockConfirm).toHaveBeenCalledWith({\n default: false,\n message: expect.stringContaining(\n 'Migration directory /test/path/migrations/my-migration already exists. Overwrite?',\n ),\n })\n expect(mockMkdir).toHaveBeenCalled()\n })\n\n test('does not create directory when user declines overwrite', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockConfirm.mockResolvedValue(false)\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockConfirm).toHaveBeenCalled()\n expect(mockMkdir).not.toHaveBeenCalled()\n })\n\n test('creates directory after user confirms overwrite', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockConfirm.mockResolvedValue(true)\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockConfirm).toHaveBeenCalled()\n expect(mockMkdir).toHaveBeenCalledWith(\n expect.stringContaining('test/path/migrations/my-migration'),\n {\n recursive: true,\n },\n )\n })\n\n test('exits gracefully when directory creation fails', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockMkdir.mockRejectedValue(new Error('Permission denied'))\n\n const {error} = await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(error).toBeDefined()\n expect(error?.message).toContain('Failed to create migration directory: Permission denied')\n expect(mockWriteFile).not.toHaveBeenCalled()\n })\n\n test('output migration instructions after migrations folder has been created', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n const {stdout} = await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockWriteFile).toHaveBeenCalled()\n\n expect(stdout).toMatchInlineSnapshot(`\n \"\n ✓ Migration created!\n\n Next steps:\n Open /test/path/migrations/my-migration/index.ts in your code editor and write the code for your migration.\n Dry run the migration with:\n \\`sanity migration run my-migration --project=<projectId> --dataset <dataset> \\`\n Run the migration against a dataset with:\n \\`sanity migration run my-migration --project=<projectId> --dataset <dataset> --no-dry-run\\`\n\n 👉 Learn more about schema and content migrations at https://www.sanity.io/docs/schema-and-content-migrations\n \"\n `)\n })\n\n test('creates minimalSimple template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Minimalistic migration to get you started')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.minimalSimple).toHaveBeenCalled()\n })\n\n test('creates renameType template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename an object type')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.renameType).toHaveBeenCalled()\n })\n\n test('creates renameField template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.renameField).toHaveBeenCalled()\n })\n\n test('creates stringToPTE template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Convert string field to Portable Text')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.stringToPTE).toHaveBeenCalled()\n })\n\n test('creates minimalAdvanced template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue(\n 'Advanced template using async iterators providing more fine grained control',\n )\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.minimalAdvanced).toHaveBeenCalled()\n })\n\n test('exits gracefully when writing the template to the directory fails', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue(\n 'Advanced template using async iterators providing more fine grained control',\n )\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n mockWriteFile.mockRejectedValue(new Error('Permission denied'))\n\n const {error, stdout} = await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(error).toBeDefined()\n expect(error?.message).toContain('Failed to create migration file: Permission denied')\n expect(stdout).toBe('')\n })\n})\n"],"names":["access","mkdir","writeFile","runCommand","testCommand","afterEach","beforeEach","describe","expect","test","vi","CreateMigrationCommand","mocks","hoisted","confirm","fn","findProjectRoot","input","select","mockTemplates","minimalAdvanced","minimalSimple","renameField","renameType","stringToPTE","mock","actual","importActual","mockConfirm","mockFindProjectRoot","mockInput","mockSelect","mockAccess","mocked","mockMkdir","mockWriteFile","mockResolvedValue","directory","root","type","clearAllMocks","stdout","toMatchInlineSnapshot","toHaveBeenCalledWith","message","validate","any","Function","mockRejectedValue","Error","error","toContain","mockResolvedValueOnce","calls","toStrictEqual","choices","name","value","stringContaining","recursive","not","toHaveBeenCalled","default","toBeDefined","toBe"],"mappings":"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"}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { readdir } from 'node:fs/promises';
|
|
2
|
-
import { runCommand } from '@oclif/test';
|
|
3
|
-
import { testCommand } from '@sanity/cli-test';
|
|
4
|
-
import { afterEach, describe, expect, test, vi } from 'vitest';
|
|
5
|
-
import { resolveMigrationScript } from '../../../utils/migration/resolveMigrationScript.js';
|
|
6
|
-
import { ListMigrationCommand } from '../list.js';
|
|
7
|
-
vi.mock('node:fs/promises', ()=>({
|
|
8
|
-
readdir: vi.fn()
|
|
9
|
-
}));
|
|
10
|
-
vi.mock('../../../../../cli-core/src/config/findProjectRoot.js', ()=>({
|
|
11
|
-
findProjectRoot: vi.fn().mockResolvedValue({
|
|
12
|
-
directory: '/test/project',
|
|
13
|
-
root: '/test/project',
|
|
14
|
-
type: 'studio'
|
|
15
|
-
})
|
|
16
|
-
}));
|
|
17
|
-
vi.mock('../../../../../cli-core/src/config/cli/getCliConfig.js', ()=>({
|
|
18
|
-
getCliConfig: vi.fn().mockResolvedValue({
|
|
19
|
-
api: {
|
|
20
|
-
projectId: 'test-project'
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
}));
|
|
24
|
-
vi.mock('../../../utils/migration/resolveMigrationScript.js', async (importOriginal)=>{
|
|
25
|
-
const actual = await importOriginal();
|
|
26
|
-
return {
|
|
27
|
-
...actual,
|
|
28
|
-
isLoadableMigrationScript: actual.isLoadableMigrationScript,
|
|
29
|
-
resolveMigrationScript: vi.fn()
|
|
30
|
-
};
|
|
31
|
-
});
|
|
32
|
-
const mockReaddir = vi.mocked(readdir);
|
|
33
|
-
const mockResolveMigrationScript = vi.mocked(resolveMigrationScript);
|
|
34
|
-
describe('#migration:list', ()=>{
|
|
35
|
-
afterEach(()=>{
|
|
36
|
-
vi.clearAllMocks();
|
|
37
|
-
});
|
|
38
|
-
test('--help works', async ()=>{
|
|
39
|
-
const { stdout } = await runCommand([
|
|
40
|
-
'migration list',
|
|
41
|
-
'--help'
|
|
42
|
-
]);
|
|
43
|
-
expect(stdout).toMatchInlineSnapshot(`
|
|
44
|
-
"List available migrations
|
|
45
|
-
|
|
46
|
-
USAGE
|
|
47
|
-
$ sanity migration list
|
|
48
|
-
|
|
49
|
-
DESCRIPTION
|
|
50
|
-
List available migrations
|
|
51
|
-
|
|
52
|
-
EXAMPLES
|
|
53
|
-
List all available migrations in the project
|
|
54
|
-
|
|
55
|
-
$ sanity migration list
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
`);
|
|
59
|
-
});
|
|
60
|
-
test('lists migrations successfully with various formats', async ()=>{
|
|
61
|
-
// Mock readdir to return both files and directories with different extensions
|
|
62
|
-
mockReaddir.mockResolvedValue([
|
|
63
|
-
{
|
|
64
|
-
isDirectory: ()=>false,
|
|
65
|
-
name: 'add-author-field.ts'
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
isDirectory: ()=>true,
|
|
69
|
-
name: 'migration-dir'
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
isDirectory: ()=>false,
|
|
73
|
-
name: 'rename-tags.js'
|
|
74
|
-
}
|
|
75
|
-
]);
|
|
76
|
-
// Mock resolveMigrationScript for .ts file
|
|
77
|
-
mockResolveMigrationScript.mockResolvedValueOnce([
|
|
78
|
-
{
|
|
79
|
-
absolutePath: '/test/project/migrations/add-author-field.ts',
|
|
80
|
-
mod: {
|
|
81
|
-
default: {
|
|
82
|
-
migrate: vi.fn(),
|
|
83
|
-
title: 'Add author field to articles'
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
relativePath: 'migrations/add-author-field.ts'
|
|
87
|
-
}
|
|
88
|
-
]);
|
|
89
|
-
// Mock resolveMigrationScript for directory
|
|
90
|
-
mockResolveMigrationScript.mockResolvedValueOnce([
|
|
91
|
-
{
|
|
92
|
-
absolutePath: '/test/project/migrations/migration-dir/index.ts',
|
|
93
|
-
mod: {
|
|
94
|
-
default: {
|
|
95
|
-
migrate: vi.fn(),
|
|
96
|
-
title: 'Directory-based migration'
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
relativePath: 'migrations/migration-dir/index.ts'
|
|
100
|
-
}
|
|
101
|
-
]);
|
|
102
|
-
// Mock resolveMigrationScript for .js file
|
|
103
|
-
mockResolveMigrationScript.mockResolvedValueOnce([
|
|
104
|
-
{
|
|
105
|
-
absolutePath: '/test/project/migrations/rename-tags.js',
|
|
106
|
-
mod: {
|
|
107
|
-
default: {
|
|
108
|
-
migrate: vi.fn(),
|
|
109
|
-
title: 'Rename tags to categories'
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
relativePath: 'migrations/rename-tags.js'
|
|
113
|
-
}
|
|
114
|
-
]);
|
|
115
|
-
const { stdout } = await testCommand(ListMigrationCommand, []);
|
|
116
|
-
// Verify count
|
|
117
|
-
expect(stdout).toContain('Found 3 migrations in project');
|
|
118
|
-
// Verify .ts file (extension removed)
|
|
119
|
-
expect(stdout).toContain('add-author-field');
|
|
120
|
-
expect(stdout).not.toContain('add-author-field.ts');
|
|
121
|
-
expect(stdout).toContain('Add author field to articles');
|
|
122
|
-
// Verify directory
|
|
123
|
-
expect(stdout).toContain('migration-dir');
|
|
124
|
-
expect(stdout).toContain('Directory-based migration');
|
|
125
|
-
// Verify .js file (extension removed)
|
|
126
|
-
expect(stdout).toContain('rename-tags');
|
|
127
|
-
expect(stdout).not.toContain('rename-tags.js');
|
|
128
|
-
expect(stdout).toContain('Rename tags to categories');
|
|
129
|
-
expect(stdout).toContain('Run `sanity migration run <ID>` to run a migration');
|
|
130
|
-
});
|
|
131
|
-
test('handles empty migrations folder', async ()=>{
|
|
132
|
-
// Mock readdir to return empty array
|
|
133
|
-
mockReaddir.mockResolvedValue([]);
|
|
134
|
-
const { stdout } = await testCommand(ListMigrationCommand, []);
|
|
135
|
-
expect(stdout).toContain('No migrations found in migrations folder of the project');
|
|
136
|
-
expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration');
|
|
137
|
-
});
|
|
138
|
-
test('handles missing migrations folder', async ()=>{
|
|
139
|
-
// Mock readdir to throw ENOENT error
|
|
140
|
-
const enoentError = new Error('ENOENT: no such file or directory');
|
|
141
|
-
Object.assign(enoentError, {
|
|
142
|
-
code: 'ENOENT'
|
|
143
|
-
});
|
|
144
|
-
mockReaddir.mockRejectedValue(enoentError);
|
|
145
|
-
const { stdout } = await testCommand(ListMigrationCommand, []);
|
|
146
|
-
expect(stdout).toContain('No migrations folder found in the project');
|
|
147
|
-
expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration');
|
|
148
|
-
});
|
|
149
|
-
test('handles migration loading errors', async ()=>{
|
|
150
|
-
// Mock readdir to return migration files
|
|
151
|
-
mockReaddir.mockResolvedValue([
|
|
152
|
-
{
|
|
153
|
-
isDirectory: ()=>false,
|
|
154
|
-
name: 'broken-migration.ts'
|
|
155
|
-
}
|
|
156
|
-
]);
|
|
157
|
-
// Mock resolveMigrationScript to throw error
|
|
158
|
-
mockResolveMigrationScript.mockRejectedValue(new Error('Syntax error in migration file'));
|
|
159
|
-
const { error } = await testCommand(ListMigrationCommand, []);
|
|
160
|
-
expect(error?.message).toContain('List migrations failed');
|
|
161
|
-
expect(error?.message).toContain('Syntax error in migration file');
|
|
162
|
-
expect(error?.oclif?.exit).toBe(1);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
//# sourceMappingURL=list.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/commands/migration/__tests__/list.test.ts"],"sourcesContent":["import {readdir} from 'node:fs/promises'\n\nimport {runCommand} from '@oclif/test'\nimport {testCommand} from '@sanity/cli-test'\nimport {type Migration} from '@sanity/migrate'\nimport {afterEach, describe, expect, test, vi} from 'vitest'\n\nimport {resolveMigrationScript} from '../../../utils/migration/resolveMigrationScript.js'\nimport {ListMigrationCommand} from '../list.js'\n\nvi.mock('node:fs/promises', () => ({\n readdir: vi.fn(),\n}))\n\nvi.mock('../../../../../cli-core/src/config/findProjectRoot.js', () => ({\n findProjectRoot: vi.fn().mockResolvedValue({\n directory: '/test/project',\n root: '/test/project',\n type: 'studio',\n }),\n}))\n\nvi.mock('../../../../../cli-core/src/config/cli/getCliConfig.js', () => ({\n getCliConfig: vi.fn().mockResolvedValue({\n api: {\n projectId: 'test-project',\n },\n }),\n}))\n\nvi.mock('../../../utils/migration/resolveMigrationScript.js', async (importOriginal) => {\n const actual =\n await importOriginal<typeof import('../../../utils/migration/resolveMigrationScript.js')>()\n return {\n ...actual,\n isLoadableMigrationScript: actual.isLoadableMigrationScript,\n resolveMigrationScript: vi.fn(),\n }\n})\n\nconst mockReaddir = vi.mocked(readdir)\nconst mockResolveMigrationScript = vi.mocked(resolveMigrationScript)\n\ndescribe('#migration:list', () => {\n afterEach(() => {\n vi.clearAllMocks()\n })\n\n test('--help works', async () => {\n const {stdout} = await runCommand(['migration list', '--help'])\n expect(stdout).toMatchInlineSnapshot(`\n \"List available migrations\n\n USAGE\n $ sanity migration list\n\n DESCRIPTION\n List available migrations\n\n EXAMPLES\n List all available migrations in the project\n\n $ sanity migration list\n\n \"\n `)\n })\n\n test('lists migrations successfully with various formats', async () => {\n // Mock readdir to return both files and directories with different extensions\n mockReaddir.mockResolvedValue([\n {isDirectory: () => false, name: 'add-author-field.ts'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n {isDirectory: () => true, name: 'migration-dir'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n {isDirectory: () => false, name: 'rename-tags.js'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n ])\n\n // Mock resolveMigrationScript for .ts file\n mockResolveMigrationScript.mockResolvedValueOnce([\n {\n absolutePath: '/test/project/migrations/add-author-field.ts',\n mod: {\n default: {\n migrate: vi.fn(),\n title: 'Add author field to articles',\n } as Migration,\n },\n relativePath: 'migrations/add-author-field.ts',\n },\n ])\n\n // Mock resolveMigrationScript for directory\n mockResolveMigrationScript.mockResolvedValueOnce([\n {\n absolutePath: '/test/project/migrations/migration-dir/index.ts',\n mod: {\n default: {\n migrate: vi.fn(),\n title: 'Directory-based migration',\n } as Migration,\n },\n relativePath: 'migrations/migration-dir/index.ts',\n },\n ])\n\n // Mock resolveMigrationScript for .js file\n mockResolveMigrationScript.mockResolvedValueOnce([\n {\n absolutePath: '/test/project/migrations/rename-tags.js',\n mod: {\n default: {\n migrate: vi.fn(),\n title: 'Rename tags to categories',\n } as Migration,\n },\n relativePath: 'migrations/rename-tags.js',\n },\n ])\n\n const {stdout} = await testCommand(ListMigrationCommand, [])\n\n // Verify count\n expect(stdout).toContain('Found 3 migrations in project')\n\n // Verify .ts file (extension removed)\n expect(stdout).toContain('add-author-field')\n expect(stdout).not.toContain('add-author-field.ts')\n expect(stdout).toContain('Add author field to articles')\n\n // Verify directory\n expect(stdout).toContain('migration-dir')\n expect(stdout).toContain('Directory-based migration')\n\n // Verify .js file (extension removed)\n expect(stdout).toContain('rename-tags')\n expect(stdout).not.toContain('rename-tags.js')\n expect(stdout).toContain('Rename tags to categories')\n\n expect(stdout).toContain('Run `sanity migration run <ID>` to run a migration')\n })\n\n test('handles empty migrations folder', async () => {\n // Mock readdir to return empty array\n mockReaddir.mockResolvedValue([])\n\n const {stdout} = await testCommand(ListMigrationCommand, [])\n\n expect(stdout).toContain('No migrations found in migrations folder of the project')\n expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration')\n })\n\n test('handles missing migrations folder', async () => {\n // Mock readdir to throw ENOENT error\n const enoentError = new Error('ENOENT: no such file or directory')\n Object.assign(enoentError, {code: 'ENOENT'})\n mockReaddir.mockRejectedValue(enoentError)\n\n const {stdout} = await testCommand(ListMigrationCommand, [])\n\n expect(stdout).toContain('No migrations folder found in the project')\n expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration')\n })\n\n test('handles migration loading errors', async () => {\n // Mock readdir to return migration files\n mockReaddir.mockResolvedValue([\n {isDirectory: () => false, name: 'broken-migration.ts'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n ])\n\n // Mock resolveMigrationScript to throw error\n mockResolveMigrationScript.mockRejectedValue(new Error('Syntax error in migration file'))\n\n const {error} = await testCommand(ListMigrationCommand, [])\n\n expect(error?.message).toContain('List migrations failed')\n expect(error?.message).toContain('Syntax error in migration file')\n expect(error?.oclif?.exit).toBe(1)\n })\n})\n"],"names":["readdir","runCommand","testCommand","afterEach","describe","expect","test","vi","resolveMigrationScript","ListMigrationCommand","mock","fn","findProjectRoot","mockResolvedValue","directory","root","type","getCliConfig","api","projectId","importOriginal","actual","isLoadableMigrationScript","mockReaddir","mocked","mockResolveMigrationScript","clearAllMocks","stdout","toMatchInlineSnapshot","isDirectory","name","mockResolvedValueOnce","absolutePath","mod","default","migrate","title","relativePath","toContain","not","enoentError","Error","Object","assign","code","mockRejectedValue","error","message","oclif","exit","toBe"],"mappings":"AAAA,SAAQA,OAAO,QAAO,mBAAkB;AAExC,SAAQC,UAAU,QAAO,cAAa;AACtC,SAAQC,WAAW,QAAO,mBAAkB;AAE5C,SAAQC,SAAS,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,IAAI,EAAEC,EAAE,QAAO,SAAQ;AAE5D,SAAQC,sBAAsB,QAAO,qDAAoD;AACzF,SAAQC,oBAAoB,QAAO,aAAY;AAE/CF,GAAGG,IAAI,CAAC,oBAAoB,IAAO,CAAA;QACjCV,SAASO,GAAGI,EAAE;IAChB,CAAA;AAEAJ,GAAGG,IAAI,CAAC,yDAAyD,IAAO,CAAA;QACtEE,iBAAiBL,GAAGI,EAAE,GAAGE,iBAAiB,CAAC;YACzCC,WAAW;YACXC,MAAM;YACNC,MAAM;QACR;IACF,CAAA;AAEAT,GAAGG,IAAI,CAAC,0DAA0D,IAAO,CAAA;QACvEO,cAAcV,GAAGI,EAAE,GAAGE,iBAAiB,CAAC;YACtCK,KAAK;gBACHC,WAAW;YACb;QACF;IACF,CAAA;AAEAZ,GAAGG,IAAI,CAAC,sDAAsD,OAAOU;IACnE,MAAMC,SACJ,MAAMD;IACR,OAAO;QACL,GAAGC,MAAM;QACTC,2BAA2BD,OAAOC,yBAAyB;QAC3Dd,wBAAwBD,GAAGI,EAAE;IAC/B;AACF;AAEA,MAAMY,cAAchB,GAAGiB,MAAM,CAACxB;AAC9B,MAAMyB,6BAA6BlB,GAAGiB,MAAM,CAAChB;AAE7CJ,SAAS,mBAAmB;IAC1BD,UAAU;QACRI,GAAGmB,aAAa;IAClB;IAEApB,KAAK,gBAAgB;QACnB,MAAM,EAACqB,MAAM,EAAC,GAAG,MAAM1B,WAAW;YAAC;YAAkB;SAAS;QAC9DI,OAAOsB,QAAQC,qBAAqB,CAAC,CAAC;;;;;;;;;;;;;;;IAetC,CAAC;IACH;IAEAtB,KAAK,sDAAsD;QACzD,8EAA8E;QAC9EiB,YAAYV,iBAAiB,CAAC;YAC5B;gBAACgB,aAAa,IAAM;gBAAOC,MAAM;YAAqB;YAGtD;gBAACD,aAAa,IAAM;gBAAMC,MAAM;YAAe;YAG/C;gBAACD,aAAa,IAAM;gBAAOC,MAAM;YAAgB;SAGlD;QAED,2CAA2C;QAC3CL,2BAA2BM,qBAAqB,CAAC;YAC/C;gBACEC,cAAc;gBACdC,KAAK;oBACHC,SAAS;wBACPC,SAAS5B,GAAGI,EAAE;wBACdyB,OAAO;oBACT;gBACF;gBACAC,cAAc;YAChB;SACD;QAED,4CAA4C;QAC5CZ,2BAA2BM,qBAAqB,CAAC;YAC/C;gBACEC,cAAc;gBACdC,KAAK;oBACHC,SAAS;wBACPC,SAAS5B,GAAGI,EAAE;wBACdyB,OAAO;oBACT;gBACF;gBACAC,cAAc;YAChB;SACD;QAED,2CAA2C;QAC3CZ,2BAA2BM,qBAAqB,CAAC;YAC/C;gBACEC,cAAc;gBACdC,KAAK;oBACHC,SAAS;wBACPC,SAAS5B,GAAGI,EAAE;wBACdyB,OAAO;oBACT;gBACF;gBACAC,cAAc;YAChB;SACD;QAED,MAAM,EAACV,MAAM,EAAC,GAAG,MAAMzB,YAAYO,sBAAsB,EAAE;QAE3D,eAAe;QACfJ,OAAOsB,QAAQW,SAAS,CAAC;QAEzB,sCAAsC;QACtCjC,OAAOsB,QAAQW,SAAS,CAAC;QACzBjC,OAAOsB,QAAQY,GAAG,CAACD,SAAS,CAAC;QAC7BjC,OAAOsB,QAAQW,SAAS,CAAC;QAEzB,mBAAmB;QACnBjC,OAAOsB,QAAQW,SAAS,CAAC;QACzBjC,OAAOsB,QAAQW,SAAS,CAAC;QAEzB,sCAAsC;QACtCjC,OAAOsB,QAAQW,SAAS,CAAC;QACzBjC,OAAOsB,QAAQY,GAAG,CAACD,SAAS,CAAC;QAC7BjC,OAAOsB,QAAQW,SAAS,CAAC;QAEzBjC,OAAOsB,QAAQW,SAAS,CAAC;IAC3B;IAEAhC,KAAK,mCAAmC;QACtC,qCAAqC;QACrCiB,YAAYV,iBAAiB,CAAC,EAAE;QAEhC,MAAM,EAACc,MAAM,EAAC,GAAG,MAAMzB,YAAYO,sBAAsB,EAAE;QAE3DJ,OAAOsB,QAAQW,SAAS,CAAC;QACzBjC,OAAOsB,QAAQW,SAAS,CAAC;IAC3B;IAEAhC,KAAK,qCAAqC;QACxC,qCAAqC;QACrC,MAAMkC,cAAc,IAAIC,MAAM;QAC9BC,OAAOC,MAAM,CAACH,aAAa;YAACI,MAAM;QAAQ;QAC1CrB,YAAYsB,iBAAiB,CAACL;QAE9B,MAAM,EAACb,MAAM,EAAC,GAAG,MAAMzB,YAAYO,sBAAsB,EAAE;QAE3DJ,OAAOsB,QAAQW,SAAS,CAAC;QACzBjC,OAAOsB,QAAQW,SAAS,CAAC;IAC3B;IAEAhC,KAAK,oCAAoC;QACvC,yCAAyC;QACzCiB,YAAYV,iBAAiB,CAAC;YAC5B;gBAACgB,aAAa,IAAM;gBAAOC,MAAM;YAAqB;SAGvD;QAED,6CAA6C;QAC7CL,2BAA2BoB,iBAAiB,CAAC,IAAIJ,MAAM;QAEvD,MAAM,EAACK,KAAK,EAAC,GAAG,MAAM5C,YAAYO,sBAAsB,EAAE;QAE1DJ,OAAOyC,OAAOC,SAAST,SAAS,CAAC;QACjCjC,OAAOyC,OAAOC,SAAST,SAAS,CAAC;QACjCjC,OAAOyC,OAAOE,OAAOC,MAAMC,IAAI,CAAC;IAClC;AACF"}
|