@sentry/wizard 6.12.0 → 6.13.0

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 (184) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/bin.js +16 -1
  3. package/dist/bin.js.map +1 -1
  4. package/dist/e2e-tests/tests/angular-17.test.js +3 -4
  5. package/dist/e2e-tests/tests/angular-17.test.js.map +1 -1
  6. package/dist/e2e-tests/tests/angular-19.test.js +3 -4
  7. package/dist/e2e-tests/tests/angular-19.test.js.map +1 -1
  8. package/dist/e2e-tests/tests/flutter.test.js +60 -0
  9. package/dist/e2e-tests/tests/flutter.test.js.map +1 -1
  10. package/dist/e2e-tests/tests/help-message.test.js +8 -3
  11. package/dist/e2e-tests/tests/help-message.test.js.map +1 -1
  12. package/dist/e2e-tests/tests/nuxt-3.test.js +12 -6
  13. package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -1
  14. package/dist/e2e-tests/tests/nuxt-4.test.js +12 -6
  15. package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -1
  16. package/dist/e2e-tests/tests/pnpm-workspace.test.js +6 -3
  17. package/dist/e2e-tests/tests/pnpm-workspace.test.js.map +1 -1
  18. package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js +4 -4
  19. package/dist/e2e-tests/tests/react-router-instrumentation-api.test.js.map +1 -1
  20. package/dist/e2e-tests/tests/react-router.test.js +3 -6
  21. package/dist/e2e-tests/tests/react-router.test.js.map +1 -1
  22. package/dist/e2e-tests/tests/remix.test.js +2 -4
  23. package/dist/e2e-tests/tests/remix.test.js.map +1 -1
  24. package/dist/e2e-tests/tests/sveltekit-hooks.test.js +24 -8
  25. package/dist/e2e-tests/tests/sveltekit-hooks.test.js.map +1 -1
  26. package/dist/e2e-tests/tests/sveltekit-tracing.test.js +6 -3
  27. package/dist/e2e-tests/tests/sveltekit-tracing.test.js.map +1 -1
  28. package/dist/lib/Constants.d.ts +1 -0
  29. package/dist/lib/Constants.js +5 -0
  30. package/dist/lib/Constants.js.map +1 -1
  31. package/dist/lib/Steps/Integrations/Electron.js +2 -2
  32. package/dist/lib/Steps/Integrations/Electron.js.map +1 -1
  33. package/dist/src/android/android-wizard.js +3 -0
  34. package/dist/src/android/android-wizard.js.map +1 -1
  35. package/dist/src/angular/codemods/main.d.ts +1 -1
  36. package/dist/src/angular/codemods/main.js +0 -1
  37. package/dist/src/angular/codemods/main.js.map +1 -1
  38. package/dist/src/apple/apple-wizard.js +2 -3
  39. package/dist/src/apple/apple-wizard.js.map +1 -1
  40. package/dist/src/apple/check-installed-cli.d.ts +1 -1
  41. package/dist/src/apple/check-installed-cli.js +13 -7
  42. package/dist/src/apple/check-installed-cli.js.map +1 -1
  43. package/dist/src/apple/configure-xcode-project.js +8 -1
  44. package/dist/src/apple/configure-xcode-project.js.map +1 -1
  45. package/dist/src/apple/lookup-xcode-project.d.ts +8 -5
  46. package/dist/src/apple/lookup-xcode-project.js +22 -17
  47. package/dist/src/apple/lookup-xcode-project.js.map +1 -1
  48. package/dist/src/apple/options.d.ts +5 -0
  49. package/dist/src/apple/options.js.map +1 -1
  50. package/dist/src/apple/sentry-swift-package.d.ts +4 -0
  51. package/dist/src/apple/sentry-swift-package.js +17 -0
  52. package/dist/src/apple/sentry-swift-package.js.map +1 -0
  53. package/dist/src/apple/snapshots/apple-snapshots-wizard.d.ts +2 -0
  54. package/dist/src/apple/snapshots/apple-snapshots-wizard.js +251 -0
  55. package/dist/src/apple/snapshots/apple-snapshots-wizard.js.map +1 -0
  56. package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.d.ts +13 -0
  57. package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.js +48 -0
  58. package/dist/src/apple/snapshots/configure-snapshotpreviews-xcode-project.js.map +1 -0
  59. package/dist/src/apple/snapshots/snapshot-test-file.d.ts +18 -0
  60. package/dist/src/apple/snapshots/snapshot-test-file.js +122 -0
  61. package/dist/src/apple/snapshots/snapshot-test-file.js.map +1 -0
  62. package/dist/src/apple/snapshots/snapshot-verification-scheme.d.ts +6 -0
  63. package/dist/src/apple/snapshots/snapshot-verification-scheme.js +147 -0
  64. package/dist/src/apple/snapshots/snapshot-verification-scheme.js.map +1 -0
  65. package/dist/src/apple/snapshots/snapshotpreviews-package.d.ts +4 -0
  66. package/dist/src/apple/snapshots/snapshotpreviews-package.js +8 -0
  67. package/dist/src/apple/snapshots/snapshotpreviews-package.js.map +1 -0
  68. package/dist/src/apple/snapshots/snapshots-cli-preflight.d.ts +23 -0
  69. package/dist/src/apple/snapshots/snapshots-cli-preflight.js +136 -0
  70. package/dist/src/apple/snapshots/snapshots-cli-preflight.js.map +1 -0
  71. package/dist/src/apple/xcode-manager.d.ts +59 -1
  72. package/dist/src/apple/xcode-manager.js +507 -106
  73. package/dist/src/apple/xcode-manager.js.map +1 -1
  74. package/dist/src/flutter/flutter-wizard.js +3 -0
  75. package/dist/src/flutter/flutter-wizard.js.map +1 -1
  76. package/dist/src/nextjs/templates.js +12 -6
  77. package/dist/src/nextjs/templates.js.map +1 -1
  78. package/dist/src/nuxt/templates.js +12 -6
  79. package/dist/src/nuxt/templates.js.map +1 -1
  80. package/dist/src/react-router/codemods/client.entry.d.ts +1 -1
  81. package/dist/src/react-router/codemods/client.entry.js +93 -52
  82. package/dist/src/react-router/codemods/client.entry.js.map +1 -1
  83. package/dist/src/react-router/codemods/server-entry.js +8 -7
  84. package/dist/src/react-router/codemods/server-entry.js.map +1 -1
  85. package/dist/src/react-router/react-router-wizard.js +13 -19
  86. package/dist/src/react-router/react-router-wizard.js.map +1 -1
  87. package/dist/src/react-router/sdk-setup.d.ts +2 -2
  88. package/dist/src/react-router/sdk-setup.js +16 -15
  89. package/dist/src/react-router/sdk-setup.js.map +1 -1
  90. package/dist/src/react-router/templates.d.ts +1 -3
  91. package/dist/src/react-router/templates.js +24 -92
  92. package/dist/src/react-router/templates.js.map +1 -1
  93. package/dist/src/remix/sdk-setup.js +1 -2
  94. package/dist/src/remix/sdk-setup.js.map +1 -1
  95. package/dist/src/run.d.ts +4 -1
  96. package/dist/src/run.js +13 -0
  97. package/dist/src/run.js.map +1 -1
  98. package/dist/src/sourcemaps/tools/remix.js +4 -4
  99. package/dist/src/sourcemaps/tools/remix.js.map +1 -1
  100. package/dist/src/sveltekit/sdk-setup/setup.js +17 -4
  101. package/dist/src/sveltekit/sdk-setup/setup.js.map +1 -1
  102. package/dist/src/sveltekit/templates.js +12 -6
  103. package/dist/src/sveltekit/templates.js.map +1 -1
  104. package/dist/src/utils/clack/index.d.ts +2 -1
  105. package/dist/src/utils/clack/index.js +17 -6
  106. package/dist/src/utils/clack/index.js.map +1 -1
  107. package/dist/src/utils/files.d.ts +2 -0
  108. package/dist/src/utils/files.js +58 -0
  109. package/dist/src/utils/files.js.map +1 -0
  110. package/dist/src/utils/git.d.ts +3 -1
  111. package/dist/src/utils/git.js +2 -1
  112. package/dist/src/utils/git.js.map +1 -1
  113. package/dist/src/utils/line-endings.d.ts +1 -0
  114. package/dist/src/utils/line-endings.js +76 -0
  115. package/dist/src/utils/line-endings.js.map +1 -0
  116. package/dist/src/version.d.ts +1 -1
  117. package/dist/src/version.js +1 -1
  118. package/dist/src/version.js.map +1 -1
  119. package/dist/test/angular/angular-wizard.test.js +0 -5
  120. package/dist/test/angular/angular-wizard.test.js.map +1 -1
  121. package/dist/test/apple/lookup-xcode-project.test.js +167 -0
  122. package/dist/test/apple/lookup-xcode-project.test.js.map +1 -0
  123. package/dist/test/apple/snapshots/apple-snapshots-wizard.test.d.ts +1 -0
  124. package/dist/test/apple/snapshots/apple-snapshots-wizard.test.js +487 -0
  125. package/dist/test/apple/snapshots/apple-snapshots-wizard.test.js.map +1 -0
  126. package/dist/test/apple/snapshots/hosted-test-target-fixture.d.ts +24 -0
  127. package/dist/test/apple/snapshots/hosted-test-target-fixture.js +191 -0
  128. package/dist/test/apple/snapshots/hosted-test-target-fixture.js.map +1 -0
  129. package/dist/test/apple/snapshots/snapshot-test-file.test.d.ts +1 -0
  130. package/dist/test/apple/snapshots/snapshot-test-file.test.js +110 -0
  131. package/dist/test/apple/snapshots/snapshot-test-file.test.js.map +1 -0
  132. package/dist/test/apple/snapshots/snapshot-verification-scheme.test.d.ts +1 -0
  133. package/dist/test/apple/snapshots/snapshot-verification-scheme.test.js +146 -0
  134. package/dist/test/apple/snapshots/snapshot-verification-scheme.test.js.map +1 -0
  135. package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.d.ts +1 -0
  136. package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.js +186 -0
  137. package/dist/test/apple/snapshots/snapshotpreviews-xcode-smoke.test.js.map +1 -0
  138. package/dist/test/apple/snapshots/snapshots-cli-preflight.test.d.ts +1 -0
  139. package/dist/test/apple/snapshots/snapshots-cli-preflight.test.js +192 -0
  140. package/dist/test/apple/snapshots/snapshots-cli-preflight.test.js.map +1 -0
  141. package/dist/test/apple/snapshots/source-file-insertion.test.d.ts +1 -0
  142. package/dist/test/apple/snapshots/source-file-insertion.test.js +77 -0
  143. package/dist/test/apple/snapshots/source-file-insertion.test.js.map +1 -0
  144. package/dist/test/apple/xcode-manager.test.js +452 -43
  145. package/dist/test/apple/xcode-manager.test.js.map +1 -1
  146. package/dist/test/constants.test.d.ts +1 -0
  147. package/dist/test/constants.test.js +12 -0
  148. package/dist/test/constants.test.js.map +1 -0
  149. package/dist/test/nextjs/templates.test.js +66 -33
  150. package/dist/test/nextjs/templates.test.js.map +1 -1
  151. package/dist/test/nuxt/templates.test.js +66 -36
  152. package/dist/test/nuxt/templates.test.js.map +1 -1
  153. package/dist/test/react-router/codemods/client-entry.test.js +15 -11
  154. package/dist/test/react-router/codemods/client-entry.test.js.map +1 -1
  155. package/dist/test/react-router/codemods/server-entry.test.js +21 -8
  156. package/dist/test/react-router/codemods/server-entry.test.js.map +1 -1
  157. package/dist/test/react-router/sdk-setup.test.js +46 -10
  158. package/dist/test/react-router/sdk-setup.test.js.map +1 -1
  159. package/dist/test/react-router/templates.test.js +26 -64
  160. package/dist/test/react-router/templates.test.js.map +1 -1
  161. package/dist/test/remix/build-script.test.d.ts +1 -0
  162. package/dist/test/remix/build-script.test.js +124 -0
  163. package/dist/test/remix/build-script.test.js.map +1 -0
  164. package/dist/test/remix/client-entry.test.js +4 -10
  165. package/dist/test/remix/client-entry.test.js.map +1 -1
  166. package/dist/test/run.test.d.ts +1 -0
  167. package/dist/test/run.test.js +137 -0
  168. package/dist/test/run.test.js.map +1 -0
  169. package/dist/test/sveltekit/templates.test.js +78 -27
  170. package/dist/test/sveltekit/templates.test.js.map +1 -1
  171. package/dist/test/utils/clack/index.test.js +101 -0
  172. package/dist/test/utils/clack/index.test.js.map +1 -1
  173. package/dist/test/utils/git.test.js +10 -0
  174. package/dist/test/utils/git.test.js.map +1 -1
  175. package/dist/test/utils/line-endings.test.d.ts +1 -0
  176. package/dist/test/utils/line-endings.test.js +103 -0
  177. package/dist/test/utils/line-endings.test.js.map +1 -0
  178. package/package.json +2 -2
  179. package/dist/src/react-router/codemods/root.d.ts +0 -1
  180. package/dist/src/react-router/codemods/root.js +0 -170
  181. package/dist/src/react-router/codemods/root.js.map +0 -1
  182. package/dist/test/react-router/codemods/root.test.js +0 -182
  183. package/dist/test/react-router/codemods/root.test.js.map +0 -1
  184. /package/dist/test/{react-router/codemods/root.test.d.ts → apple/lookup-xcode-project.test.d.ts} +0 -0
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const fs = __importStar(require("node:fs"));
27
+ const path = __importStar(require("node:path"));
28
+ const vitest_1 = require("vitest");
29
+ const configure_snapshotpreviews_xcode_project_1 = require("../../../src/apple/snapshots/configure-snapshotpreviews-xcode-project");
30
+ const snapshot_test_file_1 = require("../../../src/apple/snapshots/snapshot-test-file");
31
+ const snapshotpreviews_package_1 = require("../../../src/apple/snapshots/snapshotpreviews-package");
32
+ const xcode_manager_1 = require("../../../src/apple/xcode-manager");
33
+ const hosted_test_target_fixture_1 = require("./hosted-test-target-fixture");
34
+ vitest_1.vi.mock('@clack/prompts', () => ({
35
+ log: {
36
+ info: vitest_1.vi.fn(),
37
+ success: vitest_1.vi.fn(),
38
+ step: vitest_1.vi.fn(),
39
+ },
40
+ }));
41
+ const projectObjectId = 'D4E604C52D50CEEC00CAB00F';
42
+ const productsGroupId = 'D4E604CE2D50CEEC00CAB00F';
43
+ const hostedTestTargetIds = {
44
+ targetId: 'AAAABBBBCCCCDDDDEEEE0001',
45
+ frameworksBuildPhaseId: 'AAAABBBBCCCCDDDDEEEE0002',
46
+ sourcesBuildPhaseId: 'AAAABBBBCCCCDDDDEEEE0003',
47
+ debugBuildConfigurationId: 'AAAABBBBCCCCDDDDEEEE0004',
48
+ releaseBuildConfigurationId: 'AAAABBBBCCCCDDDDEEEE0005',
49
+ buildConfigurationListId: 'AAAABBBBCCCCDDDDEEEE0006',
50
+ productReferenceId: 'AAAABBBBCCCCDDDDEEEE0007',
51
+ };
52
+ function getTargetByName(xcodeProject, targetName) {
53
+ const target = Object.values(xcodeProject.objects.PBXNativeTarget ?? {}).find((candidate) => {
54
+ return typeof candidate !== 'string' && candidate.name === targetName;
55
+ });
56
+ if (!target) {
57
+ throw new Error(`Target not found: ${targetName}`);
58
+ }
59
+ return target;
60
+ }
61
+ function getProductDependencyIds(xcodeProject, productName) {
62
+ return Object.entries(xcodeProject.objects.XCSwiftPackageProductDependency ?? {}).reduce((ids, [id, productDependency]) => {
63
+ if (id.endsWith('_comment') ||
64
+ typeof productDependency === 'string' ||
65
+ productDependency.productName !== productName) {
66
+ return ids;
67
+ }
68
+ return ids.concat(id);
69
+ }, new Array());
70
+ }
71
+ function getProductDependency(xcodeProject, productDependencyId) {
72
+ const productDependency = xcodeProject.objects.XCSwiftPackageProductDependency?.[productDependencyId];
73
+ if (!productDependency || typeof productDependency === 'string') {
74
+ throw new Error(`Product dependency not found: ${productDependencyId}`);
75
+ }
76
+ return productDependency;
77
+ }
78
+ function getFrameworkProductRefs(xcodeProject, targetName) {
79
+ return (getTargetByName(xcodeProject, targetName).buildPhases ?? []).reduce((productRefs, buildPhaseReference) => {
80
+ const buildPhase = xcodeProject.objects.PBXFrameworksBuildPhase?.[buildPhaseReference.value];
81
+ if (!buildPhase || typeof buildPhase === 'string') {
82
+ return productRefs;
83
+ }
84
+ return productRefs.concat((buildPhase.files ?? []).flatMap((file) => {
85
+ const buildFile = xcodeProject.objects.PBXBuildFile?.[file.value];
86
+ return buildFile &&
87
+ typeof buildFile !== 'string' &&
88
+ typeof buildFile.productRef === 'string'
89
+ ? [buildFile.productRef]
90
+ : [];
91
+ }));
92
+ }, new Array());
93
+ }
94
+ function getSnapshotPreviewsPackageReferenceIds(xcodeProject) {
95
+ return Object.entries(xcodeProject.objects.XCRemoteSwiftPackageReference ?? {}).reduce((ids, [id, packageReference]) => {
96
+ if (id.endsWith('_comment') ||
97
+ typeof packageReference === 'string' ||
98
+ packageReference.repositoryURL !== `"${snapshotpreviews_package_1.SNAPSHOTPREVIEWS_PACKAGE_URL}"`) {
99
+ return ids;
100
+ }
101
+ return ids.concat(id);
102
+ }, new Array());
103
+ }
104
+ (0, vitest_1.describe)('SnapshotPreviews hosted XCTest Xcode project smoke coverage', () => {
105
+ (0, vitest_1.it)('mutates, reparses, and reruns without duplicating package or source membership', () => {
106
+ const pbxprojPath = (0, hosted_test_target_fixture_1.copySingleTargetProjectToTemp)('snapshotpreviews-xcode-smoke-');
107
+ const xcodeProject = new xcode_manager_1.XcodeProject(pbxprojPath);
108
+ (0, hosted_test_target_fixture_1.addHostedUnitTestTarget)(xcodeProject, {
109
+ ids: hostedTestTargetIds,
110
+ includeSourcesBuildPhase: true,
111
+ projectObjectId,
112
+ productsGroupId,
113
+ });
114
+ const snapshotTestResult = (0, snapshot_test_file_1.ensureSnapshotTestFile)({
115
+ xcodeProject,
116
+ hostedTestTargetName: 'ProjectTests',
117
+ });
118
+ const packageResult = (0, configure_snapshotpreviews_xcode_project_1.configureSnapshotPreviewsXcodeProject)({
119
+ xcodeProject,
120
+ hostedTestTargetName: 'ProjectTests',
121
+ previewTargetNames: ['Project'],
122
+ });
123
+ xcodeProject.write();
124
+ (0, vitest_1.expect)(snapshotTestResult.changed).toBe(true);
125
+ (0, vitest_1.expect)(snapshotTestResult.included).toBe(true);
126
+ if (!snapshotTestResult.included) {
127
+ throw new Error('Expected snapshot test file to be included');
128
+ }
129
+ (0, vitest_1.expect)(snapshotTestResult.filePath).toBe(path.join(xcodeProject.baseDir, 'ProjectTests', 'ProjectTestsSnapshotTest.swift'));
130
+ (0, vitest_1.expect)(packageResult).toEqual({
131
+ changed: true,
132
+ failedSnapshotPreferencesTargetNames: [],
133
+ linked: true,
134
+ });
135
+ const firstSerializedProject = fs.readFileSync(pbxprojPath, 'utf8');
136
+ const reparsedProject = new xcode_manager_1.XcodeProject(pbxprojPath);
137
+ (0, vitest_1.expect)(reparsedProject.getUnitTestTargetNames()).toContain('ProjectTests');
138
+ (0, vitest_1.expect)(getSnapshotPreviewsPackageReferenceIds(reparsedProject)).toHaveLength(1);
139
+ const snapshottingTestsProductDependencyIds = getProductDependencyIds(reparsedProject, snapshotpreviews_package_1.SNAPSHOTPREVIEWS_SNAPSHOT_TESTS_PRODUCT);
140
+ const snapshotPreferencesProductDependencyIds = getProductDependencyIds(reparsedProject, snapshotpreviews_package_1.SNAPSHOTPREVIEWS_PREFERENCES_PRODUCT);
141
+ (0, vitest_1.expect)(snapshottingTestsProductDependencyIds).toHaveLength(1);
142
+ (0, vitest_1.expect)(snapshotPreferencesProductDependencyIds).toHaveLength(1);
143
+ (0, vitest_1.expect)(getProductDependency(reparsedProject, snapshottingTestsProductDependencyIds[0]).package).toBe(getSnapshotPreviewsPackageReferenceIds(reparsedProject)[0]);
144
+ (0, vitest_1.expect)(getProductDependency(reparsedProject, snapshotPreferencesProductDependencyIds[0]).package).toBe(getSnapshotPreviewsPackageReferenceIds(reparsedProject)[0]);
145
+ (0, vitest_1.expect)(getFrameworkProductRefs(reparsedProject, 'ProjectTests')).toEqual([
146
+ snapshottingTestsProductDependencyIds[0],
147
+ ]);
148
+ (0, vitest_1.expect)(getFrameworkProductRefs(reparsedProject, 'Project')).toEqual([
149
+ snapshotPreferencesProductDependencyIds[0],
150
+ ]);
151
+ (0, vitest_1.expect)(getTargetByName(reparsedProject, 'ProjectTests')
152
+ .packageProductDependencies).toEqual([
153
+ {
154
+ value: snapshottingTestsProductDependencyIds[0],
155
+ comment: snapshotpreviews_package_1.SNAPSHOTPREVIEWS_SNAPSHOT_TESTS_PRODUCT,
156
+ },
157
+ ]);
158
+ (0, vitest_1.expect)(getTargetByName(reparsedProject, 'Project').packageProductDependencies).toEqual([
159
+ {
160
+ value: snapshotPreferencesProductDependencyIds[0],
161
+ comment: snapshotpreviews_package_1.SNAPSHOTPREVIEWS_PREFERENCES_PRODUCT,
162
+ },
163
+ ]);
164
+ (0, vitest_1.expect)(reparsedProject
165
+ .getSourceFilesForTarget('ProjectTests')
166
+ ?.filter((sourceFilePath) => sourceFilePath.endsWith('ProjectTests/ProjectTestsSnapshotTest.swift'))).toHaveLength(1);
167
+ const secondSnapshotTestResult = (0, snapshot_test_file_1.ensureSnapshotTestFile)({
168
+ xcodeProject: reparsedProject,
169
+ hostedTestTargetName: 'ProjectTests',
170
+ });
171
+ const secondPackageResult = (0, configure_snapshotpreviews_xcode_project_1.configureSnapshotPreviewsXcodeProject)({
172
+ xcodeProject: reparsedProject,
173
+ hostedTestTargetName: 'ProjectTests',
174
+ previewTargetNames: ['Project'],
175
+ });
176
+ reparsedProject.write();
177
+ (0, vitest_1.expect)(secondSnapshotTestResult.changed).toBe(false);
178
+ (0, vitest_1.expect)(secondPackageResult).toEqual({
179
+ changed: false,
180
+ failedSnapshotPreferencesTargetNames: [],
181
+ linked: true,
182
+ });
183
+ (0, vitest_1.expect)(fs.readFileSync(pbxprojPath, 'utf8')).toBe(firstSerializedProject);
184
+ }, 15000);
185
+ });
186
+ //# sourceMappingURL=snapshotpreviews-xcode-smoke.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshotpreviews-xcode-smoke.test.js","sourceRoot":"","sources":["../../../../test/apple/snapshots/snapshotpreviews-xcode-smoke.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4CAA8B;AAC9B,gDAAkC;AAClC,mCAAkD;AAGlD,oIAA8H;AAC9H,wFAAyF;AACzF,oGAI+D;AAC/D,oEAAgE;AAChE,6EAGsC;AAEtC,WAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,GAAG,EAAE;QACH,IAAI,EAAE,WAAE,CAAC,EAAE,EAAE;QACb,OAAO,EAAE,WAAE,CAAC,EAAE,EAAE;QAChB,IAAI,EAAE,WAAE,CAAC,EAAE,EAAE;KACd;CACF,CAAC,CAAC,CAAC;AAEJ,MAAM,eAAe,GAAG,0BAA0B,CAAC;AACnD,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAEnD,MAAM,mBAAmB,GAAG;IAC1B,QAAQ,EAAE,0BAA0B;IACpC,sBAAsB,EAAE,0BAA0B;IAClD,mBAAmB,EAAE,0BAA0B;IAC/C,yBAAyB,EAAE,0BAA0B;IACrD,2BAA2B,EAAE,0BAA0B;IACvD,wBAAwB,EAAE,0BAA0B;IACpD,kBAAkB,EAAE,0BAA0B;CAC/C,CAAC;AAEF,SAAS,eAAe,CACtB,YAA0B,EAC1B,UAAkB;IAElB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,IAAI,CAC3E,CAAC,SAAS,EAAE,EAAE;QACZ,OAAO,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC;IACxE,CAAC,CAC6B,CAAC;IAEjC,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,IAAI,KAAK,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC;KACpD;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,uBAAuB,CAC9B,YAA0B,EAC1B,WAAmB;IAEnB,OAAO,MAAM,CAAC,OAAO,CACnB,YAAY,CAAC,OAAO,CAAC,+BAA+B,IAAI,EAAE,CAC3D,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,iBAAiB,CAAC,EAAE,EAAE;QACxC,IACE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;YACvB,OAAO,iBAAiB,KAAK,QAAQ;YACrC,iBAAiB,CAAC,WAAW,KAAK,WAAW,EAC7C;YACA,OAAO,GAAG,CAAC;SACZ;QAED,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC,EAAE,IAAI,KAAK,EAAU,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,oBAAoB,CAC3B,YAA0B,EAC1B,mBAA2B;IAE3B,MAAM,iBAAiB,GACrB,YAAY,CAAC,OAAO,CAAC,+BAA+B,EAAE,CAAC,mBAAmB,CAAC,CAAC;IAC9E,IAAI,CAAC,iBAAiB,IAAI,OAAO,iBAAiB,KAAK,QAAQ,EAAE;QAC/D,MAAM,IAAI,KAAK,CAAC,iCAAiC,mBAAmB,EAAE,CAAC,CAAC;KACzE;IAED,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,SAAS,uBAAuB,CAC9B,YAA0B,EAC1B,UAAkB;IAElB,OAAO,CAAC,eAAe,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CACzE,CAAC,WAAW,EAAE,mBAAmB,EAAE,EAAE;QACnC,MAAM,UAAU,GACd,YAAY,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAC5C,mBAAmB,CAAC,KAAK,CAC1B,CAAC;QACJ,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;YACjD,OAAO,WAAW,CAAC;SACpB;QAED,OAAO,WAAW,CAAC,MAAM,CACvB,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACxC,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClE,OAAO,SAAS;gBACd,OAAO,SAAS,KAAK,QAAQ;gBAC7B,OAAO,SAAS,CAAC,UAAU,KAAK,QAAQ;gBACxC,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;gBACxB,CAAC,CAAC,EAAE,CAAC;QACT,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,EACD,IAAI,KAAK,EAAU,CACpB,CAAC;AACJ,CAAC;AAED,SAAS,sCAAsC,CAC7C,YAA0B;IAE1B,OAAO,MAAM,CAAC,OAAO,CACnB,YAAY,CAAC,OAAO,CAAC,6BAA6B,IAAI,EAAE,CACzD,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,gBAAgB,CAAC,EAAE,EAAE;QACvC,IACE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;YACvB,OAAO,gBAAgB,KAAK,QAAQ;YACpC,gBAAgB,CAAC,aAAa,KAAK,IAAI,uDAA4B,GAAG,EACtE;YACA,OAAO,GAAG,CAAC;SACZ;QAED,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC,EAAE,IAAI,KAAK,EAAU,CAAC,CAAC;AAC1B,CAAC;AAED,IAAA,iBAAQ,EAAC,6DAA6D,EAAE,GAAG,EAAE;IAC3E,IAAA,WAAE,EAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,WAAW,GAAG,IAAA,0DAA6B,EAC/C,+BAA+B,CAChC,CAAC;QACF,MAAM,YAAY,GAAG,IAAI,4BAAY,CAAC,WAAW,CAAC,CAAC;QACnD,IAAA,oDAAuB,EAAC,YAAY,EAAE;YACpC,GAAG,EAAE,mBAAmB;YACxB,wBAAwB,EAAE,IAAI;YAC9B,eAAe;YACf,eAAe;SAChB,CAAC,CAAC;QAEH,MAAM,kBAAkB,GAAG,IAAA,2CAAsB,EAAC;YAChD,YAAY;YACZ,oBAAoB,EAAE,cAAc;SACrC,CAAC,CAAC;QACH,MAAM,aAAa,GAAG,IAAA,gFAAqC,EAAC;YAC1D,YAAY;YACZ,oBAAoB,EAAE,cAAc;YACpC,kBAAkB,EAAE,CAAC,SAAS,CAAC;SAChC,CAAC,CAAC;QACH,YAAY,CAAC,KAAK,EAAE,CAAC;QAErB,IAAA,eAAM,EAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAA,eAAM,EAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;SAC/D;QACD,IAAA,eAAM,EAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,IAAI,CACtC,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,OAAO,EACpB,cAAc,EACd,gCAAgC,CACjC,CACF,CAAC;QACF,IAAA,eAAM,EAAC,aAAa,CAAC,CAAC,OAAO,CAAC;YAC5B,OAAO,EAAE,IAAI;YACb,oCAAoC,EAAE,EAAE;YACxC,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,sBAAsB,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACpE,MAAM,eAAe,GAAG,IAAI,4BAAY,CAAC,WAAW,CAAC,CAAC;QAEtD,IAAA,eAAM,EAAC,eAAe,CAAC,sBAAsB,EAAE,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC3E,IAAA,eAAM,EACJ,sCAAsC,CAAC,eAAe,CAAC,CACxD,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAElB,MAAM,qCAAqC,GAAG,uBAAuB,CACnE,eAAe,EACf,kEAAuC,CACxC,CAAC;QACF,MAAM,uCAAuC,GAAG,uBAAuB,CACrE,eAAe,EACf,+DAAoC,CACrC,CAAC;QACF,IAAA,eAAM,EAAC,qCAAqC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9D,IAAA,eAAM,EAAC,uCAAuC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChE,IAAA,eAAM,EACJ,oBAAoB,CAClB,eAAe,EACf,qCAAqC,CAAC,CAAC,CAAC,CACzC,CAAC,OAAO,CACV,CAAC,IAAI,CAAC,sCAAsC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,IAAA,eAAM,EACJ,oBAAoB,CAClB,eAAe,EACf,uCAAuC,CAAC,CAAC,CAAC,CAC3C,CAAC,OAAO,CACV,CAAC,IAAI,CAAC,sCAAsC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,IAAA,eAAM,EAAC,uBAAuB,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC;YACvE,qCAAqC,CAAC,CAAC,CAAC;SACzC,CAAC,CAAC;QACH,IAAA,eAAM,EAAC,uBAAuB,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;YAClE,uCAAuC,CAAC,CAAC,CAAC;SAC3C,CAAC,CAAC;QAEH,IAAA,eAAM,EACJ,eAAe,CAAC,eAAe,EAAE,cAAc,CAAC;aAC7C,0BAA0B,CAC9B,CAAC,OAAO,CAAC;YACR;gBACE,KAAK,EAAE,qCAAqC,CAAC,CAAC,CAAC;gBAC/C,OAAO,EAAE,kEAAuC;aACjD;SACF,CAAC,CAAC;QACH,IAAA,eAAM,EACJ,eAAe,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,0BAA0B,CACvE,CAAC,OAAO,CAAC;YACR;gBACE,KAAK,EAAE,uCAAuC,CAAC,CAAC,CAAC;gBACjD,OAAO,EAAE,+DAAoC;aAC9C;SACF,CAAC,CAAC;QACH,IAAA,eAAM,EACJ,eAAe;aACZ,uBAAuB,CAAC,cAAc,CAAC;YACxC,EAAE,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE,CAC1B,cAAc,CAAC,QAAQ,CACrB,6CAA6C,CAC9C,CACF,CACJ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAElB,MAAM,wBAAwB,GAAG,IAAA,2CAAsB,EAAC;YACtD,YAAY,EAAE,eAAe;YAC7B,oBAAoB,EAAE,cAAc;SACrC,CAAC,CAAC;QACH,MAAM,mBAAmB,GAAG,IAAA,gFAAqC,EAAC;YAChE,YAAY,EAAE,eAAe;YAC7B,oBAAoB,EAAE,cAAc;YACpC,kBAAkB,EAAE,CAAC,SAAS,CAAC;SAChC,CAAC,CAAC;QACH,eAAe,CAAC,KAAK,EAAE,CAAC;QAExB,IAAA,eAAM,EAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,IAAA,eAAM,EAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC;YAClC,OAAO,EAAE,KAAK;YACd,oCAAoC,EAAE,EAAE;YACxC,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QACH,IAAA,eAAM,EAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC5E,CAAC,EAAE,KAAM,CAAC,CAAC;AACb,CAAC,CAAC,CAAC","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { describe, expect, it, vi } from 'vitest';\nimport type { PBXNativeTarget } from 'xcode';\n\nimport { configureSnapshotPreviewsXcodeProject } from '../../../src/apple/snapshots/configure-snapshotpreviews-xcode-project';\nimport { ensureSnapshotTestFile } from '../../../src/apple/snapshots/snapshot-test-file';\nimport {\n SNAPSHOTPREVIEWS_PACKAGE_URL,\n SNAPSHOTPREVIEWS_PREFERENCES_PRODUCT,\n SNAPSHOTPREVIEWS_SNAPSHOT_TESTS_PRODUCT,\n} from '../../../src/apple/snapshots/snapshotpreviews-package';\nimport { XcodeProject } from '../../../src/apple/xcode-manager';\nimport {\n addHostedUnitTestTarget,\n copySingleTargetProjectToTemp,\n} from './hosted-test-target-fixture';\n\nvi.mock('@clack/prompts', () => ({\n log: {\n info: vi.fn(),\n success: vi.fn(),\n step: vi.fn(),\n },\n}));\n\nconst projectObjectId = 'D4E604C52D50CEEC00CAB00F';\nconst productsGroupId = 'D4E604CE2D50CEEC00CAB00F';\n\nconst hostedTestTargetIds = {\n targetId: 'AAAABBBBCCCCDDDDEEEE0001',\n frameworksBuildPhaseId: 'AAAABBBBCCCCDDDDEEEE0002',\n sourcesBuildPhaseId: 'AAAABBBBCCCCDDDDEEEE0003',\n debugBuildConfigurationId: 'AAAABBBBCCCCDDDDEEEE0004',\n releaseBuildConfigurationId: 'AAAABBBBCCCCDDDDEEEE0005',\n buildConfigurationListId: 'AAAABBBBCCCCDDDDEEEE0006',\n productReferenceId: 'AAAABBBBCCCCDDDDEEEE0007',\n};\n\nfunction getTargetByName(\n xcodeProject: XcodeProject,\n targetName: string,\n): PBXNativeTarget {\n const target = Object.values(xcodeProject.objects.PBXNativeTarget ?? {}).find(\n (candidate) => {\n return typeof candidate !== 'string' && candidate.name === targetName;\n },\n ) as PBXNativeTarget | undefined;\n\n if (!target) {\n throw new Error(`Target not found: ${targetName}`);\n }\n\n return target;\n}\n\nfunction getProductDependencyIds(\n xcodeProject: XcodeProject,\n productName: string,\n): string[] {\n return Object.entries(\n xcodeProject.objects.XCSwiftPackageProductDependency ?? {},\n ).reduce((ids, [id, productDependency]) => {\n if (\n id.endsWith('_comment') ||\n typeof productDependency === 'string' ||\n productDependency.productName !== productName\n ) {\n return ids;\n }\n\n return ids.concat(id);\n }, new Array<string>());\n}\n\nfunction getProductDependency(\n xcodeProject: XcodeProject,\n productDependencyId: string,\n) {\n const productDependency =\n xcodeProject.objects.XCSwiftPackageProductDependency?.[productDependencyId];\n if (!productDependency || typeof productDependency === 'string') {\n throw new Error(`Product dependency not found: ${productDependencyId}`);\n }\n\n return productDependency;\n}\n\nfunction getFrameworkProductRefs(\n xcodeProject: XcodeProject,\n targetName: string,\n): string[] {\n return (getTargetByName(xcodeProject, targetName).buildPhases ?? []).reduce(\n (productRefs, buildPhaseReference) => {\n const buildPhase =\n xcodeProject.objects.PBXFrameworksBuildPhase?.[\n buildPhaseReference.value\n ];\n if (!buildPhase || typeof buildPhase === 'string') {\n return productRefs;\n }\n\n return productRefs.concat(\n (buildPhase.files ?? []).flatMap((file) => {\n const buildFile = xcodeProject.objects.PBXBuildFile?.[file.value];\n return buildFile &&\n typeof buildFile !== 'string' &&\n typeof buildFile.productRef === 'string'\n ? [buildFile.productRef]\n : [];\n }),\n );\n },\n new Array<string>(),\n );\n}\n\nfunction getSnapshotPreviewsPackageReferenceIds(\n xcodeProject: XcodeProject,\n): string[] {\n return Object.entries(\n xcodeProject.objects.XCRemoteSwiftPackageReference ?? {},\n ).reduce((ids, [id, packageReference]) => {\n if (\n id.endsWith('_comment') ||\n typeof packageReference === 'string' ||\n packageReference.repositoryURL !== `\"${SNAPSHOTPREVIEWS_PACKAGE_URL}\"`\n ) {\n return ids;\n }\n\n return ids.concat(id);\n }, new Array<string>());\n}\n\ndescribe('SnapshotPreviews hosted XCTest Xcode project smoke coverage', () => {\n it('mutates, reparses, and reruns without duplicating package or source membership', () => {\n const pbxprojPath = copySingleTargetProjectToTemp(\n 'snapshotpreviews-xcode-smoke-',\n );\n const xcodeProject = new XcodeProject(pbxprojPath);\n addHostedUnitTestTarget(xcodeProject, {\n ids: hostedTestTargetIds,\n includeSourcesBuildPhase: true,\n projectObjectId,\n productsGroupId,\n });\n\n const snapshotTestResult = ensureSnapshotTestFile({\n xcodeProject,\n hostedTestTargetName: 'ProjectTests',\n });\n const packageResult = configureSnapshotPreviewsXcodeProject({\n xcodeProject,\n hostedTestTargetName: 'ProjectTests',\n previewTargetNames: ['Project'],\n });\n xcodeProject.write();\n\n expect(snapshotTestResult.changed).toBe(true);\n expect(snapshotTestResult.included).toBe(true);\n if (!snapshotTestResult.included) {\n throw new Error('Expected snapshot test file to be included');\n }\n expect(snapshotTestResult.filePath).toBe(\n path.join(\n xcodeProject.baseDir,\n 'ProjectTests',\n 'ProjectTestsSnapshotTest.swift',\n ),\n );\n expect(packageResult).toEqual({\n changed: true,\n failedSnapshotPreferencesTargetNames: [],\n linked: true,\n });\n\n const firstSerializedProject = fs.readFileSync(pbxprojPath, 'utf8');\n const reparsedProject = new XcodeProject(pbxprojPath);\n\n expect(reparsedProject.getUnitTestTargetNames()).toContain('ProjectTests');\n expect(\n getSnapshotPreviewsPackageReferenceIds(reparsedProject),\n ).toHaveLength(1);\n\n const snapshottingTestsProductDependencyIds = getProductDependencyIds(\n reparsedProject,\n SNAPSHOTPREVIEWS_SNAPSHOT_TESTS_PRODUCT,\n );\n const snapshotPreferencesProductDependencyIds = getProductDependencyIds(\n reparsedProject,\n SNAPSHOTPREVIEWS_PREFERENCES_PRODUCT,\n );\n expect(snapshottingTestsProductDependencyIds).toHaveLength(1);\n expect(snapshotPreferencesProductDependencyIds).toHaveLength(1);\n expect(\n getProductDependency(\n reparsedProject,\n snapshottingTestsProductDependencyIds[0],\n ).package,\n ).toBe(getSnapshotPreviewsPackageReferenceIds(reparsedProject)[0]);\n expect(\n getProductDependency(\n reparsedProject,\n snapshotPreferencesProductDependencyIds[0],\n ).package,\n ).toBe(getSnapshotPreviewsPackageReferenceIds(reparsedProject)[0]);\n expect(getFrameworkProductRefs(reparsedProject, 'ProjectTests')).toEqual([\n snapshottingTestsProductDependencyIds[0],\n ]);\n expect(getFrameworkProductRefs(reparsedProject, 'Project')).toEqual([\n snapshotPreferencesProductDependencyIds[0],\n ]);\n\n expect(\n getTargetByName(reparsedProject, 'ProjectTests')\n .packageProductDependencies,\n ).toEqual([\n {\n value: snapshottingTestsProductDependencyIds[0],\n comment: SNAPSHOTPREVIEWS_SNAPSHOT_TESTS_PRODUCT,\n },\n ]);\n expect(\n getTargetByName(reparsedProject, 'Project').packageProductDependencies,\n ).toEqual([\n {\n value: snapshotPreferencesProductDependencyIds[0],\n comment: SNAPSHOTPREVIEWS_PREFERENCES_PRODUCT,\n },\n ]);\n expect(\n reparsedProject\n .getSourceFilesForTarget('ProjectTests')\n ?.filter((sourceFilePath) =>\n sourceFilePath.endsWith(\n 'ProjectTests/ProjectTestsSnapshotTest.swift',\n ),\n ),\n ).toHaveLength(1);\n\n const secondSnapshotTestResult = ensureSnapshotTestFile({\n xcodeProject: reparsedProject,\n hostedTestTargetName: 'ProjectTests',\n });\n const secondPackageResult = configureSnapshotPreviewsXcodeProject({\n xcodeProject: reparsedProject,\n hostedTestTargetName: 'ProjectTests',\n previewTargetNames: ['Project'],\n });\n reparsedProject.write();\n\n expect(secondSnapshotTestResult.changed).toBe(false);\n expect(secondPackageResult).toEqual({\n changed: false,\n failedSnapshotPreferencesTargetNames: [],\n linked: true,\n });\n expect(fs.readFileSync(pbxprojPath, 'utf8')).toBe(firstSerializedProject);\n }, 15_000);\n});\n"]}
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const fs = __importStar(require("node:fs"));
27
+ const os = __importStar(require("node:os"));
28
+ const path = __importStar(require("node:path"));
29
+ const vitest_1 = require("vitest");
30
+ const mocks = vitest_1.vi.hoisted(() => ({
31
+ askToInstallSentryCLI: vitest_1.vi.fn(),
32
+ executeSync: vitest_1.vi.fn(),
33
+ hasSentryCLI: vitest_1.vi.fn(),
34
+ info: vitest_1.vi.fn(),
35
+ installSentryCLI: vitest_1.vi.fn(),
36
+ setTag: vitest_1.vi.fn(),
37
+ success: vitest_1.vi.fn(),
38
+ warn: vitest_1.vi.fn(),
39
+ }));
40
+ vitest_1.vi.mock('@clack/prompts', () => ({
41
+ default: {
42
+ log: {
43
+ info: mocks.info,
44
+ success: mocks.success,
45
+ warn: mocks.warn,
46
+ },
47
+ },
48
+ }));
49
+ vitest_1.vi.mock('@sentry/node', () => ({
50
+ setTag: mocks.setTag,
51
+ }));
52
+ vitest_1.vi.mock('../../../src/telemetry', () => ({
53
+ traceStep: async (_name, callback) => await callback(),
54
+ }));
55
+ vitest_1.vi.mock('../../../src/utils/bash', () => ({
56
+ executeSync: mocks.executeSync,
57
+ hasSentryCLI: mocks.hasSentryCLI,
58
+ installSentryCLI: mocks.installSentryCLI,
59
+ }));
60
+ vitest_1.vi.mock('../../../src/utils/clack', () => ({
61
+ askToInstallSentryCLI: mocks.askToInstallSentryCLI,
62
+ }));
63
+ const snapshots_cli_preflight_1 = require("../../../src/apple/snapshots/snapshots-cli-preflight");
64
+ function getVerificationGuidance(projectDir) {
65
+ return {
66
+ appId: 'com.getsentry.App',
67
+ hostedTestTargetName: 'AppTests',
68
+ projectDir,
69
+ projectPath: path.join(projectDir, 'App.xcodeproj'),
70
+ schemeName: 'App',
71
+ snapshotTestClassName: 'AppTestsSnapshotTest',
72
+ };
73
+ }
74
+ (0, vitest_1.describe)('snapshots CLI preflight', () => {
75
+ (0, vitest_1.beforeEach)(() => {
76
+ vitest_1.vi.clearAllMocks();
77
+ });
78
+ (0, vitest_1.it)('offers to install sentry-cli with snapshots-aware warning when missing', async () => {
79
+ mocks.hasSentryCLI.mockReturnValue(false);
80
+ mocks.askToInstallSentryCLI.mockResolvedValue(false);
81
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-missing-'));
82
+ await (0, snapshots_cli_preflight_1.checkInstalledCLISnapshots)({
83
+ projectDir,
84
+ nonInteractive: false,
85
+ verificationGuidance: getVerificationGuidance(projectDir),
86
+ });
87
+ (0, vitest_1.expect)(mocks.askToInstallSentryCLI).toHaveBeenCalledTimes(1);
88
+ (0, vitest_1.expect)(mocks.warn).toHaveBeenCalledWith(vitest_1.expect.stringContaining('upload snapshots to Sentry'));
89
+ (0, vitest_1.expect)(mocks.executeSync).not.toHaveBeenCalled();
90
+ });
91
+ (0, vitest_1.it)('does not prompt to install sentry-cli in non-interactive mode', async () => {
92
+ mocks.hasSentryCLI.mockReturnValue(false);
93
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-non-interactive-'));
94
+ await (0, snapshots_cli_preflight_1.checkInstalledCLISnapshots)({
95
+ projectDir,
96
+ nonInteractive: true,
97
+ verificationGuidance: getVerificationGuidance(projectDir),
98
+ });
99
+ (0, vitest_1.expect)(mocks.askToInstallSentryCLI).not.toHaveBeenCalled();
100
+ (0, vitest_1.expect)(mocks.warn).toHaveBeenCalledWith(vitest_1.expect.stringContaining('upload snapshots to Sentry'));
101
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('sentry-cli snapshots upload'));
102
+ (0, vitest_1.expect)(mocks.executeSync).not.toHaveBeenCalled();
103
+ });
104
+ (0, vitest_1.it)('verifies snapshots upload support and prefers existing Fastlane guidance', async () => {
105
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));
106
+ const fastlaneDir = path.join(projectDir, 'fastlane');
107
+ fs.mkdirSync(fastlaneDir);
108
+ fs.writeFileSync(path.join(fastlaneDir, 'Fastfile'), 'platform :ios do\n lane :upload_sentry_snapshots do |options|\n sentry_upload_snapshots(path: options[:path])\n end\nend\n');
109
+ mocks.hasSentryCLI.mockReturnValue(true);
110
+ await (0, snapshots_cli_preflight_1.checkInstalledCLISnapshots)({
111
+ projectDir,
112
+ nonInteractive: false,
113
+ verificationGuidance: getVerificationGuidance(projectDir),
114
+ });
115
+ (0, vitest_1.expect)(mocks.executeSync).toHaveBeenCalledWith('sentry-cli snapshots upload --help');
116
+ (0, vitest_1.expect)(mocks.success).toHaveBeenCalledWith('sentry-cli snapshots upload is available.');
117
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('xcodebuild test'));
118
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('-project App.xcodeproj'));
119
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('-scheme App'));
120
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('-only-testing:AppTests/AppTestsSnapshotTest'));
121
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('bundle exec fastlane ios upload_sentry_snapshots'));
122
+ });
123
+ (0, vitest_1.it)('prints xcodebuild export and sentry-cli upload guidance', async () => {
124
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));
125
+ mocks.hasSentryCLI.mockReturnValue(true);
126
+ await (0, snapshots_cli_preflight_1.checkInstalledCLISnapshots)({
127
+ projectDir,
128
+ nonInteractive: false,
129
+ verificationGuidance: getVerificationGuidance(projectDir),
130
+ });
131
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('TEST_RUNNER_SNAPSHOTS_EXPORT_DIR'));
132
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('-only-testing:AppTests/AppTestsSnapshotTest'));
133
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('sentry-cli snapshots upload'));
134
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('--app-id com.getsentry.App'));
135
+ });
136
+ (0, vitest_1.it)('uses the provided snapshot test class name in xcodebuild guidance', async () => {
137
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));
138
+ mocks.hasSentryCLI.mockReturnValue(true);
139
+ await (0, snapshots_cli_preflight_1.checkInstalledCLISnapshots)({
140
+ projectDir,
141
+ nonInteractive: false,
142
+ verificationGuidance: {
143
+ ...getVerificationGuidance(projectDir),
144
+ snapshotTestClassName: 'CustomSnapshots',
145
+ },
146
+ });
147
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('-only-testing:AppTests/CustomSnapshots'));
148
+ (0, vitest_1.expect)(mocks.info).not.toHaveBeenCalledWith(vitest_1.expect.stringContaining('-only-testing:AppTests/AppTestsSnapshotTest'));
149
+ });
150
+ (0, vitest_1.it)('uses a scheme placeholder when no verification scheme was detected', async () => {
151
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));
152
+ mocks.hasSentryCLI.mockReturnValue(true);
153
+ await (0, snapshots_cli_preflight_1.checkInstalledCLISnapshots)({
154
+ projectDir,
155
+ nonInteractive: false,
156
+ verificationGuidance: {
157
+ ...getVerificationGuidance(projectDir),
158
+ schemeName: undefined,
159
+ },
160
+ });
161
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('-scheme <scheme>'));
162
+ (0, vitest_1.expect)(mocks.info).not.toHaveBeenCalledWith(vitest_1.expect.stringContaining("-scheme '<scheme>'"));
163
+ });
164
+ (0, vitest_1.it)('uses an explicit app id placeholder when the bundle identifier is unavailable', async () => {
165
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));
166
+ const verificationGuidance = {
167
+ ...getVerificationGuidance(projectDir),
168
+ appId: undefined,
169
+ };
170
+ mocks.hasSentryCLI.mockReturnValue(true);
171
+ await (0, snapshots_cli_preflight_1.checkInstalledCLISnapshots)({
172
+ projectDir,
173
+ nonInteractive: false,
174
+ verificationGuidance,
175
+ });
176
+ (0, vitest_1.expect)(mocks.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('--app-id YOUR_APP_BUNDLE_ID'));
177
+ (0, vitest_1.expect)(mocks.info).not.toHaveBeenCalledWith(vitest_1.expect.stringContaining('com.example.MyApp'));
178
+ (0, vitest_1.expect)(mocks.info).not.toHaveBeenCalledWith(vitest_1.expect.stringContaining('<your-app-bundle-id>'));
179
+ });
180
+ (0, vitest_1.it)('detects existing Fastlane snapshots upload support', () => {
181
+ const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-fastlane-'));
182
+ const fastlaneDir = path.join(projectDir, 'fastlane');
183
+ fs.mkdirSync(fastlaneDir);
184
+ fs.writeFileSync(path.join(fastlaneDir, 'Fastfile'), 'lane :upload_sentry_snapshots do\n sentry_upload_snapshots(path: "snapshot-images")\nend\n');
185
+ (0, vitest_1.expect)((0, snapshots_cli_preflight_1.getSnapshotFastlaneGuidance)(projectDir)).toEqual({
186
+ fastfilePath: path.join(fastlaneDir, 'Fastfile'),
187
+ hasUploadLane: true,
188
+ hasSentryUploadAction: true,
189
+ });
190
+ });
191
+ });
192
+ //# sourceMappingURL=snapshots-cli-preflight.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshots-cli-preflight.test.js","sourceRoot":"","sources":["../../../../test/apple/snapshots/snapshots-cli-preflight.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nconst mocks = vi.hoisted(() => ({\n askToInstallSentryCLI: vi.fn(),\n executeSync: vi.fn(),\n hasSentryCLI: vi.fn(),\n info: vi.fn(),\n installSentryCLI: vi.fn(),\n setTag: vi.fn(),\n success: vi.fn(),\n warn: vi.fn(),\n}));\n\nvi.mock('@clack/prompts', () => ({\n default: {\n log: {\n info: mocks.info,\n success: mocks.success,\n warn: mocks.warn,\n },\n },\n}));\n\nvi.mock('@sentry/node', () => ({\n setTag: mocks.setTag,\n}));\n\nvi.mock('../../../src/telemetry', () => ({\n traceStep: async (_name: string, callback: () => Promise<boolean>) =>\n await callback(),\n}));\n\nvi.mock('../../../src/utils/bash', () => ({\n executeSync: mocks.executeSync,\n hasSentryCLI: mocks.hasSentryCLI,\n installSentryCLI: mocks.installSentryCLI,\n}));\n\nvi.mock('../../../src/utils/clack', () => ({\n askToInstallSentryCLI: mocks.askToInstallSentryCLI,\n}));\n\nimport {\n checkInstalledCLISnapshots,\n getSnapshotFastlaneGuidance,\n} from '../../../src/apple/snapshots/snapshots-cli-preflight';\n\nfunction getVerificationGuidance(projectDir: string) {\n return {\n appId: 'com.getsentry.App',\n hostedTestTargetName: 'AppTests',\n projectDir,\n projectPath: path.join(projectDir, 'App.xcodeproj'),\n schemeName: 'App',\n snapshotTestClassName: 'AppTestsSnapshotTest',\n };\n}\n\ndescribe('snapshots CLI preflight', () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n it('offers to install sentry-cli with snapshots-aware warning when missing', async () => {\n mocks.hasSentryCLI.mockReturnValue(false);\n mocks.askToInstallSentryCLI.mockResolvedValue(false);\n\n const projectDir = fs.mkdtempSync(\n path.join(os.tmpdir(), 'snapshot-cli-missing-'),\n );\n\n await checkInstalledCLISnapshots({\n projectDir,\n nonInteractive: false,\n verificationGuidance: getVerificationGuidance(projectDir),\n });\n\n expect(mocks.askToInstallSentryCLI).toHaveBeenCalledTimes(1);\n expect(mocks.warn).toHaveBeenCalledWith(\n expect.stringContaining('upload snapshots to Sentry'),\n );\n expect(mocks.executeSync).not.toHaveBeenCalled();\n });\n\n it('does not prompt to install sentry-cli in non-interactive mode', async () => {\n mocks.hasSentryCLI.mockReturnValue(false);\n\n const projectDir = fs.mkdtempSync(\n path.join(os.tmpdir(), 'snapshot-cli-non-interactive-'),\n );\n\n await checkInstalledCLISnapshots({\n projectDir,\n nonInteractive: true,\n verificationGuidance: getVerificationGuidance(projectDir),\n });\n\n expect(mocks.askToInstallSentryCLI).not.toHaveBeenCalled();\n expect(mocks.warn).toHaveBeenCalledWith(\n expect.stringContaining('upload snapshots to Sentry'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('sentry-cli snapshots upload'),\n );\n expect(mocks.executeSync).not.toHaveBeenCalled();\n });\n\n it('verifies snapshots upload support and prefers existing Fastlane guidance', async () => {\n const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));\n const fastlaneDir = path.join(projectDir, 'fastlane');\n fs.mkdirSync(fastlaneDir);\n fs.writeFileSync(\n path.join(fastlaneDir, 'Fastfile'),\n 'platform :ios do\\n lane :upload_sentry_snapshots do |options|\\n sentry_upload_snapshots(path: options[:path])\\n end\\nend\\n',\n );\n mocks.hasSentryCLI.mockReturnValue(true);\n\n await checkInstalledCLISnapshots({\n projectDir,\n nonInteractive: false,\n verificationGuidance: getVerificationGuidance(projectDir),\n });\n\n expect(mocks.executeSync).toHaveBeenCalledWith(\n 'sentry-cli snapshots upload --help',\n );\n expect(mocks.success).toHaveBeenCalledWith(\n 'sentry-cli snapshots upload is available.',\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('xcodebuild test'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('-project App.xcodeproj'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('-scheme App'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('-only-testing:AppTests/AppTestsSnapshotTest'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining(\n 'bundle exec fastlane ios upload_sentry_snapshots',\n ),\n );\n });\n\n it('prints xcodebuild export and sentry-cli upload guidance', async () => {\n const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));\n mocks.hasSentryCLI.mockReturnValue(true);\n\n await checkInstalledCLISnapshots({\n projectDir,\n nonInteractive: false,\n verificationGuidance: getVerificationGuidance(projectDir),\n });\n\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('TEST_RUNNER_SNAPSHOTS_EXPORT_DIR'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('-only-testing:AppTests/AppTestsSnapshotTest'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('sentry-cli snapshots upload'),\n );\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('--app-id com.getsentry.App'),\n );\n });\n\n it('uses the provided snapshot test class name in xcodebuild guidance', async () => {\n const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));\n mocks.hasSentryCLI.mockReturnValue(true);\n\n await checkInstalledCLISnapshots({\n projectDir,\n nonInteractive: false,\n verificationGuidance: {\n ...getVerificationGuidance(projectDir),\n snapshotTestClassName: 'CustomSnapshots',\n },\n });\n\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('-only-testing:AppTests/CustomSnapshots'),\n );\n expect(mocks.info).not.toHaveBeenCalledWith(\n expect.stringContaining('-only-testing:AppTests/AppTestsSnapshotTest'),\n );\n });\n\n it('uses a scheme placeholder when no verification scheme was detected', async () => {\n const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));\n mocks.hasSentryCLI.mockReturnValue(true);\n\n await checkInstalledCLISnapshots({\n projectDir,\n nonInteractive: false,\n verificationGuidance: {\n ...getVerificationGuidance(projectDir),\n schemeName: undefined,\n },\n });\n\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('-scheme <scheme>'),\n );\n expect(mocks.info).not.toHaveBeenCalledWith(\n expect.stringContaining(\"-scheme '<scheme>'\"),\n );\n });\n\n it('uses an explicit app id placeholder when the bundle identifier is unavailable', async () => {\n const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snapshot-cli-'));\n const verificationGuidance = {\n ...getVerificationGuidance(projectDir),\n appId: undefined,\n };\n mocks.hasSentryCLI.mockReturnValue(true);\n\n await checkInstalledCLISnapshots({\n projectDir,\n nonInteractive: false,\n verificationGuidance,\n });\n\n expect(mocks.info).toHaveBeenCalledWith(\n expect.stringContaining('--app-id YOUR_APP_BUNDLE_ID'),\n );\n expect(mocks.info).not.toHaveBeenCalledWith(\n expect.stringContaining('com.example.MyApp'),\n );\n expect(mocks.info).not.toHaveBeenCalledWith(\n expect.stringContaining('<your-app-bundle-id>'),\n );\n });\n\n it('detects existing Fastlane snapshots upload support', () => {\n const projectDir = fs.mkdtempSync(\n path.join(os.tmpdir(), 'snapshot-fastlane-'),\n );\n const fastlaneDir = path.join(projectDir, 'fastlane');\n fs.mkdirSync(fastlaneDir);\n fs.writeFileSync(\n path.join(fastlaneDir, 'Fastfile'),\n 'lane :upload_sentry_snapshots do\\n sentry_upload_snapshots(path: \"snapshot-images\")\\nend\\n',\n );\n\n expect(getSnapshotFastlaneGuidance(projectDir)).toEqual({\n fastfilePath: path.join(fastlaneDir, 'Fastfile'),\n hasUploadLane: true,\n hasSentryUploadAction: true,\n });\n });\n});\n"]}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const fs = __importStar(require("node:fs"));
27
+ const path = __importStar(require("node:path"));
28
+ const vitest_1 = require("vitest");
29
+ const xcode_manager_1 = require("../../../src/apple/xcode-manager");
30
+ const hosted_test_target_fixture_1 = require("./hosted-test-target-fixture");
31
+ vitest_1.vi.mock('@clack/prompts', () => ({
32
+ log: {
33
+ info: vitest_1.vi.fn(),
34
+ success: vitest_1.vi.fn(),
35
+ step: vitest_1.vi.fn(),
36
+ },
37
+ }));
38
+ function sourceBuildPhaseFiles(xcodeProject) {
39
+ const phase = xcodeProject.objects.PBXSourcesBuildPhase?.['D4E604C92D50CEEC00CAB00F'];
40
+ return phase?.files ?? [];
41
+ }
42
+ (0, vitest_1.describe)('XcodeProject Swift source-file insertion', () => {
43
+ (0, vitest_1.beforeEach)(() => {
44
+ vitest_1.vi.clearAllMocks();
45
+ });
46
+ (0, vitest_1.it)('adds a Swift source file to a classic PBXSourcesBuildPhase once', () => {
47
+ const xcodeProject = new xcode_manager_1.XcodeProject((0, hosted_test_target_fixture_1.copySingleTargetProjectToTemp)('snapshot-source-file-'));
48
+ const filePath = path.join(xcodeProject.baseDir, 'ProjectTests', 'SnapshotTest.swift');
49
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
50
+ fs.writeFileSync(filePath, 'import SnapshottingTests\n', 'utf8');
51
+ const firstResult = xcodeProject.addSwiftSourceFileToTarget({
52
+ targetName: 'Project',
53
+ filePath,
54
+ });
55
+ const secondResult = xcodeProject.addSwiftSourceFileToTarget({
56
+ targetName: 'Project',
57
+ filePath,
58
+ });
59
+ (0, vitest_1.expect)(firstResult).toEqual({ changed: true, included: true });
60
+ (0, vitest_1.expect)(secondResult).toEqual({ changed: false, included: true });
61
+ (0, vitest_1.expect)(sourceBuildPhaseFiles(xcodeProject)).toHaveLength(1);
62
+ (0, vitest_1.expect)(Object.values(xcodeProject.objects.PBXFileReference ?? {}).filter((fileReference) => typeof fileReference === 'object' &&
63
+ fileReference.path === 'ProjectTests/SnapshotTest.swift')).toHaveLength(1);
64
+ });
65
+ (0, vitest_1.it)('uses synchronized root group inclusion when the file is inside a target synchronized folder', () => {
66
+ const xcodeProject = new xcode_manager_1.XcodeProject((0, hosted_test_target_fixture_1.copySingleTargetProjectToTemp)('snapshot-source-file-'));
67
+ const filePath = path.join(xcodeProject.baseDir, 'Sources', 'SnapshotTest.swift');
68
+ fs.writeFileSync(filePath, 'import SnapshottingTests\n', 'utf8');
69
+ const result = xcodeProject.addSwiftSourceFileToTarget({
70
+ targetName: 'Project',
71
+ filePath,
72
+ });
73
+ (0, vitest_1.expect)(result).toEqual({ changed: false, included: true });
74
+ (0, vitest_1.expect)(sourceBuildPhaseFiles(xcodeProject)).toEqual([]);
75
+ });
76
+ });
77
+ //# sourceMappingURL=source-file-insertion.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-file-insertion.test.js","sourceRoot":"","sources":["../../../../test/apple/snapshots/source-file-insertion.test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\nimport type { PBXSourcesBuildPhase } from 'xcode';\n\nimport { XcodeProject } from '../../../src/apple/xcode-manager';\nimport { copySingleTargetProjectToTemp } from './hosted-test-target-fixture';\n\nvi.mock('@clack/prompts', () => ({\n log: {\n info: vi.fn(),\n success: vi.fn(),\n step: vi.fn(),\n },\n}));\n\nfunction sourceBuildPhaseFiles(xcodeProject: XcodeProject): unknown[] {\n const phase = xcodeProject.objects.PBXSourcesBuildPhase?.[\n 'D4E604C92D50CEEC00CAB00F'\n ] as PBXSourcesBuildPhase | undefined;\n return phase?.files ?? [];\n}\n\ndescribe('XcodeProject Swift source-file insertion', () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n it('adds a Swift source file to a classic PBXSourcesBuildPhase once', () => {\n const xcodeProject = new XcodeProject(\n copySingleTargetProjectToTemp('snapshot-source-file-'),\n );\n const filePath = path.join(\n xcodeProject.baseDir,\n 'ProjectTests',\n 'SnapshotTest.swift',\n );\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, 'import SnapshottingTests\\n', 'utf8');\n\n const firstResult = xcodeProject.addSwiftSourceFileToTarget({\n targetName: 'Project',\n filePath,\n });\n const secondResult = xcodeProject.addSwiftSourceFileToTarget({\n targetName: 'Project',\n filePath,\n });\n\n expect(firstResult).toEqual({ changed: true, included: true });\n expect(secondResult).toEqual({ changed: false, included: true });\n expect(sourceBuildPhaseFiles(xcodeProject)).toHaveLength(1);\n expect(\n Object.values(xcodeProject.objects.PBXFileReference ?? {}).filter(\n (fileReference) =>\n typeof fileReference === 'object' &&\n fileReference.path === 'ProjectTests/SnapshotTest.swift',\n ),\n ).toHaveLength(1);\n });\n\n it('uses synchronized root group inclusion when the file is inside a target synchronized folder', () => {\n const xcodeProject = new XcodeProject(\n copySingleTargetProjectToTemp('snapshot-source-file-'),\n );\n const filePath = path.join(\n xcodeProject.baseDir,\n 'Sources',\n 'SnapshotTest.swift',\n );\n fs.writeFileSync(filePath, 'import SnapshottingTests\\n', 'utf8');\n\n const result = xcodeProject.addSwiftSourceFileToTarget({\n targetName: 'Project',\n filePath,\n });\n\n expect(result).toEqual({ changed: false, included: true });\n expect(sourceBuildPhaseFiles(xcodeProject)).toEqual([]);\n });\n});\n"]}