@lightdash/cli 2.228.1 → 2.229.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.
Files changed (177) hide show
  1. package/dist/.tsbuildinfo.build +1 -0
  2. package/package.json +4 -4
  3. package/dist/.tsbuildinfo +0 -1
  4. package/dist/config.test.d.ts +0 -2
  5. package/dist/config.test.d.ts.map +0 -1
  6. package/dist/config.test.js +0 -72
  7. package/dist/dbt/context.test.d.ts +0 -2
  8. package/dist/dbt/context.test.d.ts.map +0 -1
  9. package/dist/dbt/context.test.js +0 -152
  10. package/dist/dbt/manifest.test.d.ts +0 -2
  11. package/dist/dbt/manifest.test.d.ts.map +0 -1
  12. package/dist/dbt/manifest.test.js +0 -170
  13. package/dist/dbt/models.test.d.ts +0 -2
  14. package/dist/dbt/models.test.d.ts.map +0 -1
  15. package/dist/dbt/models.test.js +0 -139
  16. package/dist/dbt/profiles.test.d.ts +0 -2
  17. package/dist/dbt/profiles.test.d.ts.map +0 -1
  18. package/dist/dbt/profiles.test.js +0 -50
  19. package/dist/dbt/targets/athena.test.d.ts +0 -2
  20. package/dist/dbt/targets/athena.test.d.ts.map +0 -1
  21. package/dist/dbt/targets/athena.test.js +0 -78
  22. package/dist/dbt/targets/duckdb.test.d.ts +0 -2
  23. package/dist/dbt/targets/duckdb.test.d.ts.map +0 -1
  24. package/dist/dbt/targets/duckdb.test.js +0 -149
  25. package/dist/dbt/targets/redshift.test.d.ts +0 -2
  26. package/dist/dbt/targets/redshift.test.d.ts.map +0 -1
  27. package/dist/dbt/targets/redshift.test.js +0 -198
  28. package/dist/dbt/templating.test.d.ts +0 -2
  29. package/dist/dbt/templating.test.d.ts.map +0 -1
  30. package/dist/dbt/templating.test.js +0 -51
  31. package/dist/dbt/validation.test.d.ts +0 -2
  32. package/dist/dbt/validation.test.d.ts.map +0 -1
  33. package/dist/dbt/validation.test.js +0 -67
  34. package/dist/handlers/apps/appCodeFiles.test.d.ts +0 -2
  35. package/dist/handlers/apps/appCodeFiles.test.d.ts.map +0 -1
  36. package/dist/handlers/apps/appCodeFiles.test.js +0 -391
  37. package/dist/handlers/apps/appsDownload.test.d.ts +0 -2
  38. package/dist/handlers/apps/appsDownload.test.d.ts.map +0 -1
  39. package/dist/handlers/apps/appsDownload.test.js +0 -639
  40. package/dist/handlers/apps/build.test.d.ts +0 -2
  41. package/dist/handlers/apps/build.test.d.ts.map +0 -1
  42. package/dist/handlers/apps/build.test.js +0 -252
  43. package/dist/handlers/apps/createApp.test.d.ts +0 -2
  44. package/dist/handlers/apps/createApp.test.d.ts.map +0 -1
  45. package/dist/handlers/apps/createApp.test.js +0 -340
  46. package/dist/handlers/apps/pathContainment.test.d.ts +0 -2
  47. package/dist/handlers/apps/pathContainment.test.d.ts.map +0 -1
  48. package/dist/handlers/apps/pathContainment.test.js +0 -66
  49. package/dist/handlers/apps/preview.test.d.ts +0 -2
  50. package/dist/handlers/apps/preview.test.d.ts.map +0 -1
  51. package/dist/handlers/apps/preview.test.js +0 -353
  52. package/dist/handlers/apps/previewProxy.test.d.ts +0 -2
  53. package/dist/handlers/apps/previewProxy.test.d.ts.map +0 -1
  54. package/dist/handlers/apps/previewProxy.test.js +0 -178
  55. package/dist/handlers/apps/scaffolding.test.d.ts +0 -2
  56. package/dist/handlers/apps/scaffolding.test.d.ts.map +0 -1
  57. package/dist/handlers/apps/scaffolding.test.js +0 -151
  58. package/dist/handlers/apps/uploadRetry.test.d.ts +0 -2
  59. package/dist/handlers/apps/uploadRetry.test.d.ts.map +0 -1
  60. package/dist/handlers/apps/uploadRetry.test.js +0 -103
  61. package/dist/handlers/apps/validate.test.d.ts +0 -2
  62. package/dist/handlers/apps/validate.test.d.ts.map +0 -1
  63. package/dist/handlers/apps/validate.test.js +0 -526
  64. package/dist/handlers/compile.test.d.ts +0 -2
  65. package/dist/handlers/compile.test.d.ts.map +0 -1
  66. package/dist/handlers/compile.test.js +0 -151
  67. package/dist/handlers/compileProject.test.d.ts +0 -2
  68. package/dist/handlers/compileProject.test.d.ts.map +0 -1
  69. package/dist/handlers/compileProject.test.js +0 -637
  70. package/dist/handlers/compileWarehouseColumnValidation.test.d.ts +0 -2
  71. package/dist/handlers/compileWarehouseColumnValidation.test.d.ts.map +0 -1
  72. package/dist/handlers/compileWarehouseColumnValidation.test.js +0 -493
  73. package/dist/handlers/connectSnowflake.test.d.ts +0 -2
  74. package/dist/handlers/connectSnowflake.test.d.ts.map +0 -1
  75. package/dist/handlers/connectSnowflake.test.js +0 -320
  76. package/dist/handlers/contentAsCode/fileNames.test.d.ts +0 -2
  77. package/dist/handlers/contentAsCode/fileNames.test.d.ts.map +0 -1
  78. package/dist/handlers/contentAsCode/fileNames.test.js +0 -79
  79. package/dist/handlers/contentAsCode/registry.test.d.ts +0 -2
  80. package/dist/handlers/contentAsCode/registry.test.d.ts.map +0 -1
  81. package/dist/handlers/contentAsCode/registry.test.js +0 -18
  82. package/dist/handlers/contentAsCode/resource.test.d.ts +0 -2
  83. package/dist/handlers/contentAsCode/resource.test.d.ts.map +0 -1
  84. package/dist/handlers/contentAsCode/resource.test.js +0 -121
  85. package/dist/handlers/dbt/getDbtVersion.test.d.ts +0 -2
  86. package/dist/handlers/dbt/getDbtVersion.test.d.ts.map +0 -1
  87. package/dist/handlers/dbt/getDbtVersion.test.js +0 -106
  88. package/dist/handlers/deploy.test.d.ts +0 -2
  89. package/dist/handlers/deploy.test.d.ts.map +0 -1
  90. package/dist/handlers/deploy.test.js +0 -244
  91. package/dist/handlers/download.test.d.ts +0 -2
  92. package/dist/handlers/download.test.d.ts.map +0 -1
  93. package/dist/handlers/download.test.js +0 -1739
  94. package/dist/handlers/exportChartImage.test.d.ts +0 -2
  95. package/dist/handlers/exportChartImage.test.d.ts.map +0 -1
  96. package/dist/handlers/exportChartImage.test.js +0 -55
  97. package/dist/handlers/homepagesAsCode.test.d.ts +0 -2
  98. package/dist/handlers/homepagesAsCode.test.d.ts.map +0 -1
  99. package/dist/handlers/homepagesAsCode.test.js +0 -72
  100. package/dist/handlers/lint.test.d.ts +0 -2
  101. package/dist/handlers/lint.test.d.ts.map +0 -1
  102. package/dist/handlers/lint.test.js +0 -221
  103. package/dist/handlers/login.test.d.ts +0 -2
  104. package/dist/handlers/login.test.d.ts.map +0 -1
  105. package/dist/handlers/login.test.js +0 -24
  106. package/dist/handlers/metadataFile.test.d.ts +0 -2
  107. package/dist/handlers/metadataFile.test.d.ts.map +0 -1
  108. package/dist/handlers/metadataFile.test.js +0 -46
  109. package/dist/handlers/organizationContent/customRoles.test.d.ts +0 -2
  110. package/dist/handlers/organizationContent/customRoles.test.d.ts.map +0 -1
  111. package/dist/handlers/organizationContent/customRoles.test.js +0 -179
  112. package/dist/handlers/organizationContent/groups.test.d.ts +0 -2
  113. package/dist/handlers/organizationContent/groups.test.d.ts.map +0 -1
  114. package/dist/handlers/organizationContent/groups.test.js +0 -135
  115. package/dist/handlers/organizationContent/index.test.d.ts +0 -2
  116. package/dist/handlers/organizationContent/index.test.d.ts.map +0 -1
  117. package/dist/handlers/organizationContent/index.test.js +0 -212
  118. package/dist/handlers/organizationContent/themes.test.d.ts +0 -2
  119. package/dist/handlers/organizationContent/themes.test.d.ts.map +0 -1
  120. package/dist/handlers/organizationContent/themes.test.js +0 -180
  121. package/dist/handlers/organizationContent/users.test.d.ts +0 -2
  122. package/dist/handlers/organizationContent/users.test.d.ts.map +0 -1
  123. package/dist/handlers/organizationContent/users.test.js +0 -155
  124. package/dist/handlers/preAggregateAudit.test.d.ts +0 -2
  125. package/dist/handlers/preAggregateAudit.test.d.ts.map +0 -1
  126. package/dist/handlers/preAggregateAudit.test.js +0 -102
  127. package/dist/handlers/renameHandler.test.d.ts +0 -2
  128. package/dist/handlers/renameHandler.test.d.ts.map +0 -1
  129. package/dist/handlers/renameHandler.test.js +0 -189
  130. package/dist/handlers/resolveProjectFlag.test.d.ts +0 -2
  131. package/dist/handlers/resolveProjectFlag.test.d.ts.map +0 -1
  132. package/dist/handlers/resolveProjectFlag.test.js +0 -48
  133. package/dist/handlers/selectProject.test.d.ts +0 -2
  134. package/dist/handlers/selectProject.test.d.ts.map +0 -1
  135. package/dist/handlers/selectProject.test.js +0 -224
  136. package/dist/handlers/setProject.test.d.ts +0 -2
  137. package/dist/handlers/setProject.test.d.ts.map +0 -1
  138. package/dist/handlers/setProject.test.js +0 -63
  139. package/dist/handlers/slugUpdate.test.d.ts +0 -2
  140. package/dist/handlers/slugUpdate.test.d.ts.map +0 -1
  141. package/dist/handlers/slugUpdate.test.js +0 -265
  142. package/dist/handlers/timestampConversion.test.d.ts +0 -2
  143. package/dist/handlers/timestampConversion.test.d.ts.map +0 -1
  144. package/dist/handlers/timestampConversion.test.js +0 -87
  145. package/dist/handlers/upgradeCheck.test.d.ts +0 -2
  146. package/dist/handlers/upgradeCheck.test.d.ts.map +0 -1
  147. package/dist/handlers/upgradeCheck.test.js +0 -227
  148. package/dist/handlers/validate.test.d.ts +0 -2
  149. package/dist/handlers/validate.test.d.ts.map +0 -1
  150. package/dist/handlers/validate.test.js +0 -318
  151. package/dist/handlers/validateSpaceFilter.test.d.ts +0 -2
  152. package/dist/handlers/validateSpaceFilter.test.d.ts.map +0 -1
  153. package/dist/handlers/validateSpaceFilter.test.js +0 -79
  154. package/dist/handlers/warehouseConnection.test.d.ts +0 -2
  155. package/dist/handlers/warehouseConnection.test.d.ts.map +0 -1
  156. package/dist/handlers/warehouseConnection.test.js +0 -75
  157. package/dist/lightdash-config/lightdash-config.test.d.ts +0 -2
  158. package/dist/lightdash-config/lightdash-config.test.d.ts.map +0 -1
  159. package/dist/lightdash-config/lightdash-config.test.js +0 -69
  160. package/dist/prompts/fuzzySearchPrompt.test.d.ts +0 -2
  161. package/dist/prompts/fuzzySearchPrompt.test.d.ts.map +0 -1
  162. package/dist/prompts/fuzzySearchPrompt.test.js +0 -53
  163. package/dist/refsArgument.test.d.ts +0 -2
  164. package/dist/refsArgument.test.d.ts.map +0 -1
  165. package/dist/refsArgument.test.js +0 -42
  166. package/dist/releaseSafety/index.test.d.ts +0 -2
  167. package/dist/releaseSafety/index.test.d.ts.map +0 -1
  168. package/dist/releaseSafety/index.test.js +0 -154
  169. package/dist/releaseSafety/version.test.d.ts +0 -2
  170. package/dist/releaseSafety/version.test.d.ts.map +0 -1
  171. package/dist/releaseSafety/version.test.js +0 -22
  172. package/dist/skills.test.d.ts +0 -2
  173. package/dist/skills.test.d.ts.map +0 -1
  174. package/dist/skills.test.js +0 -112
  175. package/dist/terminal/contentAsCodeOutput.test.d.ts +0 -2
  176. package/dist/terminal/contentAsCodeOutput.test.d.ts.map +0 -1
  177. package/dist/terminal/contentAsCodeOutput.test.js +0 -231
@@ -1,224 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const common_1 = require("@lightdash/common");
5
- const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
6
- const config_1 = require("../config");
7
- const globalState_1 = tslib_1.__importDefault(require("../globalState"));
8
- const apiClient_1 = require("./dbt/apiClient");
9
- const selectProject_1 = require("./selectProject");
10
- vi.mock('inquirer');
11
- vi.mock('../analytics/analytics');
12
- vi.mock('./dbt/apiClient', () => ({
13
- lightdashApi: vi.fn(),
14
- }));
15
- vi.mock('../config', () => ({
16
- unsetPreviewProject: vi.fn().mockResolvedValue(undefined),
17
- }));
18
- const mockLightdashApi = apiClient_1.lightdashApi;
19
- const PREVIEW_UUID = '00000000-0000-0000-0000-000000000001';
20
- const MAIN_UUID = '00000000-0000-0000-0000-000000000002';
21
- const mockPreviewProjectResponse = (uuid) => {
22
- mockLightdashApi.mockResolvedValueOnce({
23
- projectUuid: uuid,
24
- type: common_1.ProjectType.PREVIEW,
25
- // The rest of the Project shape is irrelevant for this test
26
- });
27
- };
28
- describe('selectProject', () => {
29
- beforeEach(() => {
30
- vi.stubEnv('LIGHTDASH_PROJECT', undefined);
31
- });
32
- afterEach(() => {
33
- vi.resetAllMocks();
34
- vi.restoreAllMocks();
35
- vi.unstubAllEnvs();
36
- });
37
- it.each([true, false])('uses LIGHTDASH_PROJECT instead of an active preview and warns (non-interactive: %s)', async (nonInteractive) => {
38
- vi.stubEnv('LIGHTDASH_PROJECT', MAIN_UUID);
39
- vi.spyOn(globalState_1.default, 'isNonInteractive').mockReturnValue(nonInteractive);
40
- const log = vi
41
- .spyOn(globalState_1.default, 'log')
42
- .mockImplementation(() => { });
43
- mockPreviewProjectResponse(PREVIEW_UUID);
44
- const config = {
45
- context: {
46
- project: MAIN_UUID,
47
- previewProject: PREVIEW_UUID,
48
- previewName: 'My preview',
49
- },
50
- };
51
- expect(await (0, selectProject_1.selectProject)(config)).toEqual({
52
- projectUuid: MAIN_UUID,
53
- isPreview: false,
54
- });
55
- expect(inquirer_1.default.prompt).not.toHaveBeenCalled();
56
- expect(log).toHaveBeenCalledTimes(1);
57
- const warning = String(log.mock.calls[0][0]);
58
- expect(warning).toContain(`Using project ${MAIN_UUID} from LIGHTDASH_PROJECT`);
59
- expect(warning).toContain('active preview "My preview" ignored');
60
- expect(warning).toContain(`--project ${PREVIEW_UUID}`);
61
- });
62
- it('clears a deleted preview instead of warning when LIGHTDASH_PROJECT is set', async () => {
63
- vi.stubEnv('LIGHTDASH_PROJECT', MAIN_UUID);
64
- const log = vi.spyOn(globalState_1.default, 'log').mockImplementation(() => { });
65
- mockLightdashApi.mockRejectedValueOnce(new common_1.LightdashError({
66
- message: 'Not found',
67
- name: 'NotFoundError',
68
- statusCode: 404,
69
- data: {},
70
- }));
71
- expect(await (0, selectProject_1.selectProject)({
72
- context: { project: MAIN_UUID, previewProject: PREVIEW_UUID },
73
- })).toEqual({ projectUuid: MAIN_UUID, isPreview: false });
74
- expect(config_1.unsetPreviewProject).toHaveBeenCalledTimes(1);
75
- expect(log).not.toHaveBeenCalled();
76
- });
77
- it.each([
78
- ['no preview is active', { project: MAIN_UUID }],
79
- [
80
- 'LIGHTDASH_PROJECT points at the preview itself',
81
- { project: MAIN_UUID, previewProject: PREVIEW_UUID },
82
- ],
83
- ])('does not warn when %s', async (_label, context) => {
84
- const envProject = context.previewProject ?? MAIN_UUID;
85
- vi.stubEnv('LIGHTDASH_PROJECT', envProject);
86
- const log = vi.spyOn(globalState_1.default, 'log').mockImplementation(() => { });
87
- mockPreviewProjectResponse(PREVIEW_UUID);
88
- expect(await (0, selectProject_1.selectProject)({ context })).toEqual({
89
- projectUuid: envProject,
90
- isPreview: false,
91
- });
92
- expect(log).not.toHaveBeenCalled();
93
- });
94
- it('returns the preview project (without prompting) when the stored main and preview UUIDs are the same', async () => {
95
- // This is the misconfigured state produced by an older `set-project`
96
- // that allowed selecting a preview project as the default. Both
97
- // entries point at the same preview UUID, so the prompt would
98
- // otherwise label the same project as both "Preview" and "Production".
99
- mockPreviewProjectResponse(PREVIEW_UUID);
100
- const config = {
101
- context: {
102
- project: PREVIEW_UUID,
103
- projectName: 'my-preview',
104
- previewProject: PREVIEW_UUID,
105
- previewName: 'my-preview',
106
- },
107
- };
108
- const result = await (0, selectProject_1.selectProject)(config);
109
- expect(result).toEqual({
110
- projectUuid: PREVIEW_UUID,
111
- isPreview: true,
112
- });
113
- });
114
- it.each([undefined, MAIN_UUID])('uses an explicit --project UUID ahead of the environment (%s) and active preview', async (envProject) => {
115
- vi.stubEnv('LIGHTDASH_PROJECT', envProject);
116
- const config = {
117
- context: {
118
- project: MAIN_UUID,
119
- previewProject: PREVIEW_UUID,
120
- },
121
- };
122
- const explicitUuid = '00000000-0000-0000-0000-000000000003';
123
- const selection = await (0, selectProject_1.selectProject)(config, explicitUuid);
124
- expect(selection).toEqual({
125
- projectUuid: explicitUuid,
126
- isPreview: false,
127
- });
128
- expect(mockLightdashApi).not.toHaveBeenCalled();
129
- });
130
- it.each(['flag', 'env'])('resolves a project slug from the %s through the org projects list', async (source) => {
131
- if (source === 'env')
132
- vi.stubEnv('LIGHTDASH_PROJECT', 'jaffle-shop');
133
- const config = {
134
- context: { project: MAIN_UUID },
135
- };
136
- mockLightdashApi.mockResolvedValueOnce([
137
- { projectUuid: PREVIEW_UUID, slug: 'other', name: 'Other' },
138
- { projectUuid: MAIN_UUID, slug: 'jaffle-shop', name: 'Jaffle' },
139
- ]);
140
- const selection = await (0, selectProject_1.selectProject)(config, source === 'flag' ? 'jaffle-shop' : undefined);
141
- expect(selection).toEqual({
142
- projectUuid: MAIN_UUID,
143
- isPreview: false,
144
- });
145
- });
146
- it.each([undefined, ''])('keeps the active preview default without an environment override (%s)', async (envProject) => {
147
- vi.stubEnv('LIGHTDASH_PROJECT', envProject);
148
- vi.spyOn(globalState_1.default, 'isNonInteractive').mockReturnValue(true);
149
- mockPreviewProjectResponse(PREVIEW_UUID);
150
- expect(await (0, selectProject_1.selectProject)({
151
- context: {
152
- project: MAIN_UUID,
153
- previewProject: PREVIEW_UUID,
154
- },
155
- })).toEqual({ projectUuid: PREVIEW_UUID, isPreview: true });
156
- expect(inquirer_1.default.prompt).not.toHaveBeenCalled();
157
- });
158
- it('returns the main project when only the main project is configured', async () => {
159
- const config = {
160
- context: {
161
- project: MAIN_UUID,
162
- projectName: 'main',
163
- },
164
- };
165
- const result = await (0, selectProject_1.selectProject)(config);
166
- expect(result).toEqual({
167
- projectUuid: MAIN_UUID,
168
- isPreview: false,
169
- });
170
- expect(mockLightdashApi).not.toHaveBeenCalled();
171
- });
172
- });
173
- describe('logSelectedProject', () => {
174
- let consoleErrorSpy;
175
- beforeEach(() => {
176
- consoleErrorSpy = vi
177
- .spyOn(console, 'error')
178
- .mockImplementation(() => { });
179
- });
180
- afterEach(() => {
181
- consoleErrorSpy.mockRestore();
182
- });
183
- const getLoggedMessage = () => consoleErrorSpy.mock.calls.map((call) => String(call[0])).join('\n');
184
- it('shows the config project name when the selected UUID matches the config project', () => {
185
- const config = {
186
- context: {
187
- project: MAIN_UUID,
188
- projectName: 'main',
189
- },
190
- };
191
- (0, selectProject_1.logSelectedProject)({ projectUuid: MAIN_UUID, isPreview: false }, config, 'Uploading to');
192
- const output = getLoggedMessage();
193
- expect(output).toContain('Uploading to project:');
194
- expect(output).toContain('"main"');
195
- });
196
- it('shows the UUID (not the config project name) when --project overrides to a different project', () => {
197
- const OVERRIDE_UUID = '00000000-0000-0000-0000-000000000099';
198
- const config = {
199
- context: {
200
- project: MAIN_UUID,
201
- projectName: 'main',
202
- },
203
- };
204
- (0, selectProject_1.logSelectedProject)({ projectUuid: OVERRIDE_UUID, isPreview: false }, config, 'Uploading to');
205
- const output = getLoggedMessage();
206
- expect(output).toContain('Uploading to project:');
207
- expect(output).toContain(OVERRIDE_UUID);
208
- expect(output).not.toContain('"main"');
209
- });
210
- it('shows the preview name when selection is a preview', () => {
211
- const config = {
212
- context: {
213
- project: MAIN_UUID,
214
- projectName: 'main',
215
- previewProject: PREVIEW_UUID,
216
- previewName: 'my-preview',
217
- },
218
- };
219
- (0, selectProject_1.logSelectedProject)({ projectUuid: PREVIEW_UUID, isPreview: true }, config, 'Uploading to');
220
- const output = getLoggedMessage();
221
- expect(output).toContain('Uploading to preview project:');
222
- expect(output).toContain('"my-preview"');
223
- });
224
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=setProject.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"setProject.test.d.ts","sourceRoot":"","sources":["../../src/handlers/setProject.test.ts"],"names":[],"mappings":""}
@@ -1,63 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const common_1 = require("@lightdash/common");
5
- const config_1 = require("../config");
6
- const globalState_1 = tslib_1.__importDefault(require("../globalState"));
7
- const fuzzySearchPrompt_1 = require("../prompts/fuzzySearchPrompt");
8
- const apiClient_1 = require("./dbt/apiClient");
9
- const setProject_1 = require("./setProject");
10
- vi.mock('../prompts/fuzzySearchPrompt', () => ({
11
- promptFuzzySearch: vi.fn(),
12
- }));
13
- vi.mock('../analytics/analytics');
14
- vi.mock('./dbt/apiClient', () => ({
15
- lightdashApi: vi.fn(),
16
- }));
17
- vi.mock('../config', () => ({
18
- getConfig: vi.fn().mockResolvedValue({ context: {} }),
19
- setProject: vi.fn().mockResolvedValue(undefined),
20
- unsetProject: vi.fn().mockResolvedValue(undefined),
21
- }));
22
- const mockLightdashApi = apiClient_1.lightdashApi;
23
- const mockPromptFuzzySearch = fuzzySearchPrompt_1.promptFuzzySearch;
24
- const mockSetProjectConfig = config_1.setProject;
25
- const MAIN_UUID = '00000000-0000-0000-0000-000000000001';
26
- const PREVIEW_UUID = '00000000-0000-0000-0000-000000000002';
27
- const buildProjects = () => [
28
- {
29
- projectUuid: MAIN_UUID,
30
- name: 'main-project',
31
- type: common_1.ProjectType.DEFAULT,
32
- },
33
- {
34
- projectUuid: PREVIEW_UUID,
35
- name: 'a-preview',
36
- type: common_1.ProjectType.PREVIEW,
37
- },
38
- ];
39
- describe('setProjectCommand', () => {
40
- const originalIsNonInteractive = globalState_1.default.isNonInteractive;
41
- beforeEach(() => {
42
- vi.clearAllMocks();
43
- globalState_1.default.isNonInteractive = vi.fn().mockReturnValue(false);
44
- });
45
- afterAll(() => {
46
- globalState_1.default.isNonInteractive = originalIsNonInteractive;
47
- });
48
- it('does not offer preview projects in the interactive list', async () => {
49
- mockLightdashApi.mockResolvedValueOnce(buildProjects());
50
- mockPromptFuzzySearch.mockResolvedValueOnce(MAIN_UUID);
51
- await (0, setProject_1.setProjectCommand)();
52
- const promptArgs = mockPromptFuzzySearch.mock.calls[0][0];
53
- const choices = promptArgs.choices.map((c) => c.value);
54
- expect(choices).toContain(MAIN_UUID);
55
- expect(choices).not.toContain(PREVIEW_UUID);
56
- expect(mockSetProjectConfig).toHaveBeenCalledWith(MAIN_UUID, 'main-project');
57
- });
58
- it('throws when --uuid points to a preview project', async () => {
59
- mockLightdashApi.mockResolvedValueOnce(buildProjects());
60
- await expect((0, setProject_1.setProjectCommand)(undefined, PREVIEW_UUID)).rejects.toThrow(/preview project/);
61
- expect(mockSetProjectConfig).not.toHaveBeenCalled();
62
- });
63
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=slugUpdate.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"slugUpdate.test.d.ts","sourceRoot":"","sources":["../../src/handlers/slugUpdate.test.ts"],"names":[],"mappings":""}
@@ -1,265 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const common_1 = require("@lightdash/common");
5
- const fs_1 = require("fs");
6
- const os_1 = require("os");
7
- const path = tslib_1.__importStar(require("path"));
8
- const vitest_1 = require("vitest");
9
- const yaml_1 = require("yaml");
10
- const apiClient = tslib_1.__importStar(require("./dbt/apiClient"));
11
- const slugUpdate_1 = require("./slugUpdate");
12
- const temporaryDirectories = [];
13
- const createTemporaryContent = async () => {
14
- const root = await fs_1.promises.mkdtemp(path.join((0, os_1.tmpdir)(), 'slug-update-'));
15
- temporaryDirectories.push(root);
16
- await Promise.all(['charts', 'dashboards', 'alerts'].map((folder) => fs_1.promises.mkdir(path.join(root, folder), { recursive: true })));
17
- return root;
18
- };
19
- (0, vitest_1.afterEach)(async () => {
20
- vitest_1.vi.restoreAllMocks();
21
- await Promise.all(temporaryDirectories
22
- .splice(0)
23
- .map((directory) => fs_1.promises.rm(directory, { recursive: true, force: true })));
24
- });
25
- (0, vitest_1.describe)('local dashboard slug updates', () => {
26
- (0, vitest_1.test)('updates only dashboard identity, language maps, deliveries, and dashboard metadata', async () => {
27
- const root = await createTemporaryContent();
28
- const dashboardFile = path.join(root, 'dashboards', 'old-overview.yml');
29
- const mapFile = path.join(root, 'dashboards', 'old-overview.language.map.yml');
30
- const chartFile = path.join(root, 'charts', 'old-overview.yml');
31
- const chartSource = 'contentType: chart\nslug: old-overview\nmetricQuery: {}\n';
32
- const alertFile = path.join(root, 'alerts', 'delivery.yml');
33
- await Promise.all([
34
- fs_1.promises.writeFile(dashboardFile, 'contentType: dashboard\nslug: old-overview\ntiles:\n - type: saved_chart\n properties:\n chartSlug: old-overview\n'),
35
- fs_1.promises.writeFile(mapFile, 'dashboard:\n old-overview:\n name: Overview\n'),
36
- fs_1.promises.writeFile(chartFile, chartSource),
37
- fs_1.promises.writeFile(alertFile, 'resource:\n type: dashboard\n slug: old-overview\n'),
38
- fs_1.promises.writeFile(path.join(root, '.lightdash-metadata.json'), JSON.stringify({
39
- version: 1,
40
- charts: { 'old-overview': 'chart-timestamp' },
41
- dashboards: { 'old-overview': 'dashboard-timestamp' },
42
- })),
43
- ]);
44
- const plan = await (0, slugUpdate_1.planLocalSlugUpdate)(root, 'old-overview', 'overview', common_1.ContentType.DASHBOARD);
45
- (0, vitest_1.expect)(await fs_1.promises.readFile(dashboardFile, 'utf8')).toContain('slug: old-overview');
46
- await (0, slugUpdate_1.applyLocalSlugUpdate)(plan);
47
- const dashboard = (0, yaml_1.parse)(await fs_1.promises.readFile(path.join(root, 'dashboards', 'overview.yml'), 'utf8'));
48
- (0, vitest_1.expect)(dashboard.slug).toBe('overview');
49
- (0, vitest_1.expect)(dashboard.tiles[0].properties.chartSlug).toBe('old-overview');
50
- (0, vitest_1.expect)((0, yaml_1.parse)(await fs_1.promises.readFile(path.join(root, 'dashboards', 'overview.language.map.yml'), 'utf8'))).toEqual({
51
- dashboard: { overview: { name: 'Overview' } },
52
- });
53
- (0, vitest_1.expect)((0, yaml_1.parse)(await fs_1.promises.readFile(alertFile, 'utf8')).resource.slug).toBe('overview');
54
- (0, vitest_1.expect)(await fs_1.promises.readFile(chartFile, 'utf8')).toBe(chartSource);
55
- (0, vitest_1.expect)(JSON.parse(await fs_1.promises.readFile(path.join(root, '.lightdash-metadata.json'), 'utf8'))).toEqual({
56
- version: 1,
57
- charts: { 'old-overview': 'chart-timestamp' },
58
- dashboards: { overview: 'dashboard-timestamp' },
59
- });
60
- const replay = await (0, slugUpdate_1.planLocalSlugUpdate)(root, 'old-overview', 'overview', common_1.ContentType.DASHBOARD);
61
- (0, vitest_1.expect)((0, slugUpdate_1.getLocalSlugUpdateFileChanges)(replay, root)).toEqual([]);
62
- });
63
- (0, vitest_1.test)('sends the dashboard type before changing local files', async () => {
64
- const root = await createTemporaryContent();
65
- const dashboardFile = path.join(root, 'dashboards', 'old-overview.yml');
66
- const source = 'slug: old-overview\ntiles: []\n';
67
- await fs_1.promises.writeFile(dashboardFile, source);
68
- const api = vitest_1.vi
69
- .spyOn(apiClient, 'lightdashApi')
70
- .mockImplementation(async () => {
71
- (0, vitest_1.expect)(await fs_1.promises.readFile(dashboardFile, 'utf8')).toBe(source);
72
- return undefined;
73
- });
74
- await (0, slugUpdate_1.executeSlugUpdate)('project-uuid', root, 'old-overview', 'overview', common_1.ContentType.DASHBOARD);
75
- (0, vitest_1.expect)(JSON.parse(api.mock.calls[0][0].body)).toEqual({
76
- resourceType: common_1.ContentType.DASHBOARD,
77
- from: 'old-overview',
78
- to: 'overview',
79
- });
80
- });
81
- });
82
- (0, vitest_1.describe)('local chart slug updates', () => {
83
- (0, vitest_1.test)('updates chart files, language maps, references, filenames, and metadata', async () => {
84
- const root = await createTemporaryContent();
85
- const chartFile = path.join(root, 'charts', 'copy-of-orders.yml');
86
- const languageMapFile = path.join(root, 'charts', 'copy-of-orders.language.map.yml');
87
- const dashboardFile = path.join(root, 'dashboards', 'overview.yml');
88
- const alertFile = path.join(root, 'alerts', 'orders-alert.yml');
89
- const unrelatedFile = path.join(root, 'dashboards', 'unrelated.yml');
90
- const unrelatedSource = '# Keep this file byte-identical\ncontentType: dashboard\nslug: unrelated\ntiles: []\n';
91
- await Promise.all([
92
- fs_1.promises.writeFile(chartFile, '# Chart comment\ncontentType: chart\nslug: copy-of-orders\nname: Orders\nmetricQuery: {}\n'),
93
- fs_1.promises.writeFile(languageMapFile, 'chart:\n copy-of-orders:\n name: Orders\n'),
94
- fs_1.promises.writeFile(dashboardFile, [
95
- 'contentType: dashboard',
96
- 'slug: overview',
97
- 'tiles:',
98
- ' - type: saved_chart',
99
- ' tileSlug: copy-of-orders',
100
- ' properties:',
101
- ' chartSlug: copy-of-orders',
102
- ' - type: sql_chart',
103
- ' properties:',
104
- ' chartSlug: copy-of-orders',
105
- '',
106
- ].join('\n')),
107
- fs_1.promises.writeFile(alertFile, 'contentType: alert\nslug: orders-alert\nresource:\n type: chart\n slug: copy-of-orders\n'),
108
- fs_1.promises.writeFile(unrelatedFile, unrelatedSource),
109
- fs_1.promises.writeFile(path.join(root, '.lightdash-metadata.json'), JSON.stringify({
110
- version: 1,
111
- charts: { 'copy-of-orders': 'timestamp' },
112
- dashboards: { overview: 'dashboard-timestamp' },
113
- })),
114
- ]);
115
- const plan = await (0, slugUpdate_1.planLocalSlugUpdate)(root, 'copy-of-orders', 'orders');
116
- (0, vitest_1.expect)(plan.referencesUpdated).toBe(4);
117
- (0, vitest_1.expect)(plan.fileMoves).toHaveLength(2);
118
- (0, vitest_1.expect)((0, slugUpdate_1.getLocalSlugUpdateFileChanges)(plan, root)).toEqual([
119
- { source: '.lightdash-metadata.json' },
120
- { source: path.join('alerts', 'orders-alert.yml') },
121
- {
122
- source: path.join('charts', 'copy-of-orders.language.map.yml'),
123
- target: path.join('charts', 'orders.language.map.yml'),
124
- },
125
- {
126
- source: path.join('charts', 'copy-of-orders.yml'),
127
- target: path.join('charts', 'orders.yml'),
128
- },
129
- { source: path.join('dashboards', 'overview.yml') },
130
- ]);
131
- await (0, slugUpdate_1.applyLocalSlugUpdate)(plan);
132
- await (0, vitest_1.expect)(fs_1.promises.access(chartFile)).rejects.toThrow();
133
- await (0, vitest_1.expect)(fs_1.promises.access(languageMapFile)).rejects.toThrow();
134
- const renamedChart = (0, yaml_1.parse)(await fs_1.promises.readFile(path.join(root, 'charts', 'orders.yml'), 'utf8'));
135
- (0, vitest_1.expect)(renamedChart.slug).toBe('orders');
136
- (0, vitest_1.expect)(await fs_1.promises.readFile(path.join(root, 'charts', 'orders.yml'), 'utf8')).toContain('# Chart comment');
137
- const languageMap = (0, yaml_1.parse)(await fs_1.promises.readFile(path.join(root, 'charts', 'orders.language.map.yml'), 'utf8'));
138
- (0, vitest_1.expect)(languageMap.chart.orders.name).toBe('Orders');
139
- (0, vitest_1.expect)(languageMap.chart['copy-of-orders']).toBeUndefined();
140
- const dashboard = (0, yaml_1.parse)(await fs_1.promises.readFile(dashboardFile, 'utf8'));
141
- (0, vitest_1.expect)(dashboard.tiles[0]).toMatchObject({
142
- tileSlug: 'copy-of-orders',
143
- properties: { chartSlug: 'orders' },
144
- });
145
- (0, vitest_1.expect)(dashboard.tiles[1].properties.chartSlug).toBe('copy-of-orders');
146
- (0, vitest_1.expect)((0, yaml_1.parse)(await fs_1.promises.readFile(alertFile, 'utf8')).resource.slug).toBe('orders');
147
- (0, vitest_1.expect)(await fs_1.promises.readFile(unrelatedFile, 'utf8')).toBe(unrelatedSource);
148
- const metadata = JSON.parse(await fs_1.promises.readFile(path.join(root, '.lightdash-metadata.json'), 'utf8'));
149
- (0, vitest_1.expect)(metadata).toEqual({
150
- version: 1,
151
- charts: { orders: 'timestamp' },
152
- dashboards: { overview: 'dashboard-timestamp' },
153
- });
154
- });
155
- (0, vitest_1.test)('is idempotent after local files have already been updated', async () => {
156
- const root = await createTemporaryContent();
157
- await fs_1.promises.writeFile(path.join(root, 'charts', 'copy-of-orders.yml'), 'contentType: chart\nslug: copy-of-orders\nname: Orders\nmetricQuery: {}\n');
158
- await (0, slugUpdate_1.applyLocalSlugUpdate)(await (0, slugUpdate_1.planLocalSlugUpdate)(root, 'copy-of-orders', 'orders'));
159
- const secondPlan = await (0, slugUpdate_1.planLocalSlugUpdate)(root, 'copy-of-orders', 'orders');
160
- (0, vitest_1.expect)(secondPlan).toEqual({
161
- fileUpdates: [],
162
- fileMoves: [],
163
- metadata: undefined,
164
- referencesUpdated: 0,
165
- });
166
- });
167
- (0, vitest_1.test)('planning a dry run does not change local files or call the API', async () => {
168
- const root = await createTemporaryContent();
169
- const chartFile = path.join(root, 'charts', 'copy-of-orders.yml');
170
- const source = 'contentType: chart\nslug: copy-of-orders\nname: Orders\nmetricQuery: {}\n';
171
- await fs_1.promises.writeFile(chartFile, source);
172
- const api = vitest_1.vi.spyOn(apiClient, 'lightdashApi');
173
- const plan = await (0, slugUpdate_1.planLocalSlugUpdate)(root, 'copy-of-orders', 'orders');
174
- (0, vitest_1.expect)((0, slugUpdate_1.getLocalSlugUpdateFileChanges)(plan, root)).toEqual([
175
- {
176
- source: path.join('charts', 'copy-of-orders.yml'),
177
- target: path.join('charts', 'orders.yml'),
178
- },
179
- ]);
180
- (0, vitest_1.expect)(api).not.toHaveBeenCalled();
181
- (0, vitest_1.expect)(await fs_1.promises.readFile(chartFile, 'utf8')).toBe(source);
182
- await (0, vitest_1.expect)(fs_1.promises.access(path.join(root, 'charts', 'orders.yml'))).rejects.toThrow();
183
- });
184
- (0, vitest_1.test)('rejects a local target collision before changing files', async () => {
185
- const root = await createTemporaryContent();
186
- const sourceFile = path.join(root, 'charts', 'copy-of-orders.yml');
187
- await Promise.all([
188
- fs_1.promises.writeFile(sourceFile, 'contentType: chart\nslug: copy-of-orders\nname: Orders\nmetricQuery: {}\n'),
189
- fs_1.promises.writeFile(path.join(root, 'charts', 'orders.yml'), 'contentType: chart\nslug: another-chart\nname: Another\nmetricQuery: {}\n'),
190
- ]);
191
- await (0, vitest_1.expect)((0, slugUpdate_1.planLocalSlugUpdate)(root, 'copy-of-orders', 'orders')).rejects.toThrow('already exists');
192
- (0, vitest_1.expect)(await fs_1.promises.readFile(sourceFile, 'utf8')).toContain('slug: copy-of-orders');
193
- });
194
- (0, vitest_1.test)('rejects malformed target slugs before constructing file paths', async () => {
195
- const root = await createTemporaryContent();
196
- const chartFile = path.join(root, 'charts', 'copy-of-orders.yml');
197
- const source = 'contentType: chart\nslug: copy-of-orders\nname: Orders\nmetricQuery: {}\n';
198
- await fs_1.promises.writeFile(chartFile, source);
199
- await (0, vitest_1.expect)((0, slugUpdate_1.planLocalSlugUpdate)(root, 'copy-of-orders', '../../orders')).rejects.toThrow('target slug must contain');
200
- (0, vitest_1.expect)(await fs_1.promises.readFile(chartFile, 'utf8')).toBe(source);
201
- });
202
- (0, vitest_1.test)('does not change local files when the server rejects the rename', async () => {
203
- const root = await createTemporaryContent();
204
- const chartFile = path.join(root, 'charts', 'copy-of-orders.yml');
205
- const source = 'contentType: chart\nslug: copy-of-orders\nname: Orders\nmetricQuery: {}\n';
206
- await fs_1.promises.writeFile(chartFile, source);
207
- vitest_1.vi.spyOn(apiClient, 'lightdashApi').mockRejectedValue(new common_1.LightdashError({
208
- message: 'Slug already in use',
209
- name: 'ConflictError',
210
- statusCode: 409,
211
- data: {},
212
- }));
213
- await (0, vitest_1.expect)((0, slugUpdate_1.executeSlugUpdate)('project-uuid', root, 'copy-of-orders', 'orders')).rejects.toThrow('Slug already in use');
214
- (0, vitest_1.expect)(await fs_1.promises.readFile(chartFile, 'utf8')).toBe(source);
215
- await (0, vitest_1.expect)(fs_1.promises.access(path.join(root, 'charts', 'orders.yml'))).rejects.toThrow();
216
- (0, vitest_1.expect)((await fs_1.promises.readdir(path.join(root, 'charts'))).some((file) => file.includes('.slug-update-'))).toBe(false);
217
- });
218
- (0, vitest_1.test)('reserves the new slug on the server before changing local files', async () => {
219
- const root = await createTemporaryContent();
220
- const chartFile = path.join(root, 'charts', 'copy-of-orders.yml');
221
- await fs_1.promises.writeFile(chartFile, 'contentType: chart\nslug: copy-of-orders\nname: Orders\nmetricQuery: {}\n');
222
- vitest_1.vi.spyOn(apiClient, 'lightdashApi').mockImplementation(async () => {
223
- (0, vitest_1.expect)(await fs_1.promises.readFile(chartFile, 'utf8')).toContain('slug: copy-of-orders');
224
- await (0, vitest_1.expect)(fs_1.promises.access(path.join(root, 'charts', 'orders.yml'))).rejects.toThrow();
225
- return undefined;
226
- });
227
- await (0, slugUpdate_1.executeSlugUpdate)('project-uuid', root, 'copy-of-orders', 'orders');
228
- await (0, vitest_1.expect)(fs_1.promises.access(chartFile)).rejects.toThrow();
229
- (0, vitest_1.expect)(await fs_1.promises.readFile(path.join(root, 'charts', 'orders.yml'), 'utf8')).toContain('slug: orders');
230
- });
231
- });
232
- (0, vitest_1.describe)('content slug rename API', () => {
233
- (0, vitest_1.test)('calls the generic rename endpoint once', async () => {
234
- const api = vitest_1.vi
235
- .spyOn(apiClient, 'lightdashApi')
236
- .mockResolvedValue(undefined);
237
- await (0, slugUpdate_1.requestSlugUpdate)('project-uuid', {
238
- resourceType: common_1.ContentType.CHART,
239
- from: 'old-chart',
240
- to: 'new-chart',
241
- });
242
- (0, vitest_1.expect)(api).toHaveBeenCalledExactlyOnceWith({
243
- method: 'POST',
244
- url: '/api/v1/projects/project-uuid/slugs/rename',
245
- body: JSON.stringify({
246
- resourceType: common_1.ContentType.CHART,
247
- from: 'old-chart',
248
- to: 'new-chart',
249
- }),
250
- });
251
- });
252
- (0, vitest_1.test)('explains when the connected server does not support slug-update', async () => {
253
- vitest_1.vi.spyOn(apiClient, 'lightdashApi').mockRejectedValue(new common_1.LightdashError({
254
- message: 'API endpoint not found',
255
- name: 'NotFoundError',
256
- statusCode: 404,
257
- data: {},
258
- }));
259
- await (0, vitest_1.expect)((0, slugUpdate_1.requestSlugUpdate)('project-uuid', {
260
- resourceType: common_1.ContentType.CHART,
261
- from: 'old-chart',
262
- to: 'new-chart',
263
- })).rejects.toThrow('This Lightdash server does not support slug-update yet');
264
- });
265
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=timestampConversion.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"timestampConversion.test.d.ts","sourceRoot":"","sources":["../../src/handlers/timestampConversion.test.ts"],"names":[],"mappings":""}
@@ -1,87 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const common_1 = require("@lightdash/common");
4
- const apiClient_1 = require("./dbt/apiClient");
5
- const timestampConversion_1 = require("./timestampConversion");
6
- vi.mock('./dbt/apiClient', () => ({
7
- lightdashApi: vi.fn(),
8
- }));
9
- const mockLightdashApi = apiClient_1.lightdashApi;
10
- const PROJECT_UUID = '00000000-0000-0000-0000-000000000001';
11
- const snowflakeConnection = (disableTimestampConversion) => ({
12
- type: common_1.WarehouseTypes.SNOWFLAKE,
13
- ...(disableTimestampConversion !== undefined
14
- ? { disableTimestampConversion }
15
- : {}),
16
- });
17
- const postgresConnection = {
18
- type: common_1.WarehouseTypes.POSTGRES,
19
- };
20
- const mockProjectResponse = (warehouseConnection) => {
21
- mockLightdashApi.mockResolvedValueOnce({
22
- projectUuid: PROJECT_UUID,
23
- warehouseConnection,
24
- });
25
- };
26
- describe('getDisableTimestampConversionFromProject', () => {
27
- it('returns the setting for snowflake connections', () => {
28
- expect((0, timestampConversion_1.getDisableTimestampConversionFromProject)(snowflakeConnection(true))).toBe(true);
29
- expect((0, timestampConversion_1.getDisableTimestampConversionFromProject)(snowflakeConnection(false))).toBe(false);
30
- });
31
- it('returns undefined when the setting is not set', () => {
32
- expect((0, timestampConversion_1.getDisableTimestampConversionFromProject)(snowflakeConnection())).toBeUndefined();
33
- });
34
- it('returns undefined for non-snowflake connections', () => {
35
- expect((0, timestampConversion_1.getDisableTimestampConversionFromProject)(postgresConnection)).toBeUndefined();
36
- });
37
- it('returns undefined when there is no warehouse connection', () => {
38
- expect((0, timestampConversion_1.getDisableTimestampConversionFromProject)(undefined)).toBeUndefined();
39
- });
40
- });
41
- describe('getProjectDisableTimestampConversion', () => {
42
- let consoleErrorSpy;
43
- beforeEach(() => {
44
- consoleErrorSpy = vi
45
- .spyOn(console, 'error')
46
- .mockImplementation(() => { });
47
- });
48
- afterEach(() => {
49
- consoleErrorSpy.mockRestore();
50
- vi.clearAllMocks();
51
- });
52
- it('returns the project setting when the CLI flag is not provided', async () => {
53
- mockProjectResponse(snowflakeConnection(true));
54
- const result = await (0, timestampConversion_1.getProjectDisableTimestampConversion)(undefined, PROJECT_UUID);
55
- expect(result).toBe(true);
56
- expect(mockLightdashApi).toHaveBeenCalledTimes(1);
57
- expect(consoleErrorSpy).not.toHaveBeenCalled();
58
- });
59
- it('returns undefined when the snowflake project has no setting', async () => {
60
- mockProjectResponse(snowflakeConnection());
61
- const result = await (0, timestampConversion_1.getProjectDisableTimestampConversion)(undefined, PROJECT_UUID);
62
- expect(result).toBeUndefined();
63
- });
64
- it('returns undefined for non-snowflake projects', async () => {
65
- mockProjectResponse(postgresConnection);
66
- const result = await (0, timestampConversion_1.getProjectDisableTimestampConversion)(undefined, PROJECT_UUID);
67
- expect(result).toBeUndefined();
68
- });
69
- it('ignores the CLI flag, warns, and uses the project setting', async () => {
70
- mockProjectResponse(snowflakeConnection(true));
71
- const result = await (0, timestampConversion_1.getProjectDisableTimestampConversion)(false, PROJECT_UUID);
72
- expect(result).toBe(true);
73
- expect(mockLightdashApi).toHaveBeenCalledTimes(1);
74
- expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Ignoring --disable-timestamp-conversion'));
75
- });
76
- it('ignores a truthy CLI flag when the project has no setting', async () => {
77
- mockProjectResponse(snowflakeConnection());
78
- const result = await (0, timestampConversion_1.getProjectDisableTimestampConversion)(true, PROJECT_UUID);
79
- expect(result).toBeUndefined();
80
- expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Ignoring --disable-timestamp-conversion'));
81
- });
82
- it('returns undefined and does not throw when the project fetch fails', async () => {
83
- mockLightdashApi.mockRejectedValueOnce(new Error('network error'));
84
- const result = await (0, timestampConversion_1.getProjectDisableTimestampConversion)(undefined, PROJECT_UUID);
85
- expect(result).toBeUndefined();
86
- });
87
- });