@browserstack/mcp-server 1.2.2-beta.1 → 1.2.3

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 (88) hide show
  1. package/dist/lib/inmemory-store.d.ts +0 -1
  2. package/dist/lib/inmemory-store.js +0 -1
  3. package/dist/server-factory.js +0 -2
  4. package/dist/tools/bstack-sdk.d.ts +15 -2
  5. package/dist/tools/bstack-sdk.js +124 -7
  6. package/dist/tools/sdk-utils/{bstack/commands.d.ts → commands.d.ts} +1 -1
  7. package/dist/tools/sdk-utils/commands.js +65 -0
  8. package/dist/tools/sdk-utils/{bstack/frameworks.d.ts → constants.d.ts} +1 -1
  9. package/dist/tools/sdk-utils/{bstack/constants.js → constants.js} +78 -117
  10. package/dist/tools/sdk-utils/instructions.d.ts +6 -0
  11. package/dist/tools/sdk-utils/instructions.js +99 -0
  12. package/dist/tools/sdk-utils/percy/constants.d.ts +3 -0
  13. package/dist/tools/sdk-utils/{percy-bstack → percy}/constants.js +39 -13
  14. package/dist/tools/sdk-utils/percy/instructions.d.ts +10 -0
  15. package/dist/tools/sdk-utils/{percy-bstack → percy}/instructions.js +9 -5
  16. package/dist/tools/sdk-utils/percy/types.d.ts +5 -0
  17. package/package.json +1 -1
  18. package/dist/tools/add-percy-snapshots.d.ts +0 -5
  19. package/dist/tools/add-percy-snapshots.js +0 -17
  20. package/dist/tools/list-test-files.d.ts +0 -2
  21. package/dist/tools/list-test-files.js +0 -33
  22. package/dist/tools/percy-sdk.d.ts +0 -4
  23. package/dist/tools/percy-sdk.js +0 -88
  24. package/dist/tools/percy-snapshot-utils/constants.d.ts +0 -16
  25. package/dist/tools/percy-snapshot-utils/constants.js +0 -500
  26. package/dist/tools/percy-snapshot-utils/detect-test-files.d.ts +0 -10
  27. package/dist/tools/percy-snapshot-utils/detect-test-files.js +0 -194
  28. package/dist/tools/percy-snapshot-utils/types.d.ts +0 -15
  29. package/dist/tools/percy-snapshot-utils/utils.d.ts +0 -4
  30. package/dist/tools/percy-snapshot-utils/utils.js +0 -30
  31. package/dist/tools/sdk-utils/bstack/commands.js +0 -88
  32. package/dist/tools/sdk-utils/bstack/configUtils.d.ts +0 -4
  33. package/dist/tools/sdk-utils/bstack/configUtils.js +0 -66
  34. package/dist/tools/sdk-utils/bstack/constants.d.ts +0 -58
  35. package/dist/tools/sdk-utils/bstack/frameworks.js +0 -57
  36. package/dist/tools/sdk-utils/bstack/index.d.ts +0 -4
  37. package/dist/tools/sdk-utils/bstack/index.js +0 -5
  38. package/dist/tools/sdk-utils/bstack/sdkHandler.d.ts +0 -4
  39. package/dist/tools/sdk-utils/bstack/sdkHandler.js +0 -74
  40. package/dist/tools/sdk-utils/common/constants.d.ts +0 -10
  41. package/dist/tools/sdk-utils/common/constants.js +0 -86
  42. package/dist/tools/sdk-utils/common/formatUtils.d.ts +0 -5
  43. package/dist/tools/sdk-utils/common/formatUtils.js +0 -27
  44. package/dist/tools/sdk-utils/common/index.d.ts +0 -3
  45. package/dist/tools/sdk-utils/common/index.js +0 -4
  46. package/dist/tools/sdk-utils/common/instructionUtils.d.ts +0 -8
  47. package/dist/tools/sdk-utils/common/instructionUtils.js +0 -20
  48. package/dist/tools/sdk-utils/common/schema.d.ts +0 -61
  49. package/dist/tools/sdk-utils/common/schema.js +0 -28
  50. package/dist/tools/sdk-utils/common/types.d.ts +0 -66
  51. package/dist/tools/sdk-utils/common/types.js +0 -50
  52. package/dist/tools/sdk-utils/common/utils.d.ts +0 -25
  53. package/dist/tools/sdk-utils/common/utils.js +0 -84
  54. package/dist/tools/sdk-utils/handler.d.ts +0 -5
  55. package/dist/tools/sdk-utils/handler.js +0 -144
  56. package/dist/tools/sdk-utils/percy-automate/constants.d.ts +0 -11
  57. package/dist/tools/sdk-utils/percy-automate/constants.js +0 -365
  58. package/dist/tools/sdk-utils/percy-automate/frameworks.d.ts +0 -8
  59. package/dist/tools/sdk-utils/percy-automate/frameworks.js +0 -50
  60. package/dist/tools/sdk-utils/percy-automate/handler.d.ts +0 -3
  61. package/dist/tools/sdk-utils/percy-automate/handler.js +0 -30
  62. package/dist/tools/sdk-utils/percy-automate/index.d.ts +0 -1
  63. package/dist/tools/sdk-utils/percy-automate/index.js +0 -2
  64. package/dist/tools/sdk-utils/percy-automate/types.d.ts +0 -13
  65. package/dist/tools/sdk-utils/percy-automate/types.js +0 -1
  66. package/dist/tools/sdk-utils/percy-bstack/constants.d.ts +0 -4
  67. package/dist/tools/sdk-utils/percy-bstack/frameworks.d.ts +0 -2
  68. package/dist/tools/sdk-utils/percy-bstack/frameworks.js +0 -27
  69. package/dist/tools/sdk-utils/percy-bstack/handler.d.ts +0 -4
  70. package/dist/tools/sdk-utils/percy-bstack/handler.js +0 -99
  71. package/dist/tools/sdk-utils/percy-bstack/index.d.ts +0 -4
  72. package/dist/tools/sdk-utils/percy-bstack/index.js +0 -4
  73. package/dist/tools/sdk-utils/percy-bstack/instructions.d.ts +0 -7
  74. package/dist/tools/sdk-utils/percy-bstack/types.d.ts +0 -13
  75. package/dist/tools/sdk-utils/percy-bstack/types.js +0 -5
  76. package/dist/tools/sdk-utils/percy-web/constants.d.ts +0 -41
  77. package/dist/tools/sdk-utils/percy-web/constants.js +0 -941
  78. package/dist/tools/sdk-utils/percy-web/fetchPercyToken.d.ts +0 -4
  79. package/dist/tools/sdk-utils/percy-web/fetchPercyToken.js +0 -28
  80. package/dist/tools/sdk-utils/percy-web/frameworks.d.ts +0 -7
  81. package/dist/tools/sdk-utils/percy-web/frameworks.js +0 -103
  82. package/dist/tools/sdk-utils/percy-web/handler.d.ts +0 -4
  83. package/dist/tools/sdk-utils/percy-web/handler.js +0 -27
  84. package/dist/tools/sdk-utils/percy-web/index.d.ts +0 -4
  85. package/dist/tools/sdk-utils/percy-web/index.js +0 -4
  86. package/dist/tools/sdk-utils/percy-web/types.d.ts +0 -12
  87. package/dist/tools/sdk-utils/percy-web/types.js +0 -1
  88. /package/dist/tools/{percy-snapshot-utils → sdk-utils/percy}/types.js +0 -0
@@ -1,500 +0,0 @@
1
- import { z } from "zod";
2
- import { SDKSupportedLanguages, SDKSupportedTestingFrameworks, } from "../sdk-utils/common/types.js";
3
- export const UpdateTestFileWithInstructionsParams = {
4
- uuid: z
5
- .string()
6
- .describe("UUID referencing the in-memory array of test file paths"),
7
- index: z.number().describe("Index of the test file to update"),
8
- };
9
- export const ListTestFilesParamsShape = {
10
- dirs: z
11
- .array(z.string())
12
- .describe("Array of directory paths to search for test files"),
13
- language: z
14
- .enum(SDKSupportedLanguages)
15
- .describe("Programming language"),
16
- framework: z
17
- .enum(SDKSupportedTestingFrameworks)
18
- .describe("Testing framework (optional)"),
19
- };
20
- export const TEST_FILE_DETECTION = {
21
- java: {
22
- extensions: [".java"],
23
- namePatterns: [
24
- /Test\.java$/,
25
- /Tests\.java$/,
26
- /Steps\.java$/,
27
- /.*UI.*Test\.java$/,
28
- /.*Web.*Test\.java$/,
29
- /.*E2E.*Test\.java$/,
30
- /.*Integration.*Test\.java$/,
31
- /.*Functional.*Test\.java$/,
32
- ],
33
- contentRegex: [
34
- /@Test\b/,
35
- /@RunWith\b/,
36
- /@CucumberOptions\b/,
37
- /import\s+org\.junit/,
38
- /import\s+org\.testng/,
39
- /import\s+io\.cucumber/,
40
- /import\s+org\.jbehave/,
41
- ],
42
- uiDriverRegex: [
43
- /import\s+org\.openqa\.selenium/,
44
- /import\s+org\.seleniumhq\.selenium/,
45
- /import\s+io\.appium\.java_client/,
46
- /import\s+com\.microsoft\.playwright/,
47
- /import\s+com\.codeborne\.selenide/,
48
- /import\s+net\.serenitybdd/,
49
- /import\s+cucumber\.api\.java\.en/,
50
- /new\s+\w*Driver\s*\(/,
51
- /\.findElement\s*\(/,
52
- /\.get\s*\(['"]https?:/,
53
- /\.click\s*\(/,
54
- /\.navigate\(\)/,
55
- /WebDriver/,
56
- /RemoteWebDriver/,
57
- /ChromeDriver/,
58
- /FirefoxDriver/,
59
- ],
60
- uiIndicatorRegex: [
61
- // UI interactions without explicit driver imports
62
- /\.sendKeys\s*\(/,
63
- /\.getText\s*\(/,
64
- /\.isDisplayed\s*\(/,
65
- /By\.id\s*\(/,
66
- /By\.className\s*\(/,
67
- /By\.xpath\s*\(/,
68
- /waitForElement/,
69
- /waitForVisible/,
70
- /assertTitle/,
71
- /screenshot/,
72
- /captureScreenshot/,
73
- // Page Object patterns
74
- /PageObject/,
75
- /BasePage/,
76
- /WebPage/,
77
- // UI test annotations and patterns
78
- /@UITest/,
79
- /@WebTest/,
80
- /@E2ETest/,
81
- // Common UI assertions
82
- /assertUrl/,
83
- /verifyText/,
84
- /checkElement/,
85
- // Browser/window operations
86
- /maximizeWindow/,
87
- /setWindowSize/,
88
- /switchTo/,
89
- // Cucumber UI steps
90
- /Given.*I\s+(open|visit|navigate)/,
91
- /When.*I\s+(click|type|select)/,
92
- /Then.*I\s+(see|verify|check)/,
93
- /And.*I\s+(wait|scroll)/,
94
- ],
95
- backendRegex: [
96
- /import\s+org\.springframework\.test/,
97
- /import\s+javax\.persistence/,
98
- /@DataJpaTest/,
99
- /@WebMvcTest/,
100
- /@MockBean/,
101
- /EntityManager/,
102
- /JdbcTemplate/,
103
- /TestRestTemplate/,
104
- /@Repository/,
105
- /@Service/,
106
- /@Entity/,
107
- ],
108
- excludeRegex: [
109
- /UnitTest/,
110
- /MockTest/,
111
- /StubTest/,
112
- /DatabaseTest/,
113
- /import\s+org\.mockito/,
114
- /@Mock\b/,
115
- /@Spy\b/,
116
- ],
117
- },
118
- csharp: {
119
- extensions: [".cs"],
120
- namePatterns: [
121
- /Test\.cs$/,
122
- /Tests\.cs$/,
123
- /Steps\.cs$/,
124
- /.*UI.*Test\.cs$/,
125
- /.*Web.*Test\.cs$/,
126
- /.*E2E.*Test\.cs$/,
127
- ],
128
- contentRegex: [
129
- /\[Test\]/,
130
- /\[TestCase\]/,
131
- /\[Fact\]/,
132
- /\[Theory\]/,
133
- /\[Binding\]/,
134
- /using\s+NUnit\.Framework/,
135
- /using\s+Xunit/,
136
- /using\s+TechTalk\.SpecFlow/,
137
- ],
138
- uiDriverRegex: [
139
- /using\s+OpenQA\.Selenium/,
140
- /using\s+Appium/,
141
- /using\s+Microsoft\.Playwright/,
142
- /using\s+Selenide/,
143
- /using\s+Atata/,
144
- /new\s+\w*Driver\s*\(/,
145
- /\.FindElement\s*\(/,
146
- /\.Navigate\(\)/,
147
- /IWebDriver/,
148
- /WebDriver/,
149
- ],
150
- uiIndicatorRegex: [
151
- /\.SendKeys\s*\(/,
152
- /\.Click\s*\(/,
153
- /\.Text/,
154
- /\.Displayed/,
155
- /By\.Id/,
156
- /By\.ClassName/,
157
- /By\.XPath/,
158
- /WaitForElement/,
159
- /TakeScreenshot/,
160
- /PageObject/,
161
- /\[UITest\]/,
162
- /\[WebTest\]/,
163
- /\[E2ETest\]/,
164
- /NavigateTo/,
165
- /VerifyText/,
166
- /AssertUrl/,
167
- ],
168
- backendRegex: [
169
- /using\s+Microsoft\.EntityFrameworkCore/,
170
- /using\s+System\.Data/,
171
- /DbContext/,
172
- /Repository/,
173
- /Controller/,
174
- /\[ApiTest\]/,
175
- /\[DatabaseTest\]/,
176
- ],
177
- excludeRegex: [/\[UnitTest\]/, /Mock/, /Stub/, /using\s+Moq/],
178
- },
179
- nodejs: {
180
- extensions: [".js", ".ts"],
181
- namePatterns: [
182
- /.test.js$/,
183
- /.spec.js$/,
184
- /.test.ts$/,
185
- /.spec.ts$/,
186
- /.*ui.*.test.(js|ts)$/,
187
- /.*web.*.test.(js|ts)$/,
188
- /.*e2e.*.(js|ts)$/,
189
- /.*integration.*.test.(js|ts)$/,
190
- ],
191
- contentRegex: [
192
- /\bdescribe\s*\(/,
193
- /\bit\s*\(/,
194
- /\btest\s*\(/,
195
- /require\(['"]mocha['"]\)/,
196
- /require\(['"]jest['"]\)/,
197
- /import.*from\s+['"]jest['"]/,
198
- /from\s+['"]@jest/,
199
- ],
200
- uiDriverRegex: [
201
- /require\(['"]selenium-webdriver['"]\)/,
202
- /require\(['"]webdriverio['"]\)/,
203
- /require\(['"]puppeteer['"]\)/,
204
- /require\(['"]playwright['"]\)/,
205
- /require\(['"]cypress['"]\)/,
206
- /require\(['"]@wdio\/sync['"]\)/,
207
- /import.*from\s+['"]selenium-webdriver['"]/,
208
- /import.*from\s+['"]webdriverio['"]/,
209
- /import.*from\s+['"]puppeteer['"]/,
210
- /import.*from\s+['"]playwright['"]/,
211
- /import.*from\s+['"]cypress['"]/,
212
- /import.*from\s+['"]@wdio/,
213
- /\.launch\(/,
214
- /\.goto\(/,
215
- /driver\./,
216
- /browser\./,
217
- ],
218
- uiIndicatorRegex: [
219
- // Browser automation - SPECIFIC CONTEXT
220
- /driver\.click\(/,
221
- /driver\.type\(/,
222
- /driver\.fill\(/,
223
- /browser\.click\(/,
224
- /driver\.waitForSelector\(/,
225
- /browser\.waitForElement\(/,
226
- /driver\.screenshot\(/,
227
- /browser\.screenshot\(/,
228
- /driver\.evaluate\(/,
229
- /driver\.focus\(/,
230
- /driver\.hover\(/,
231
- // Page object patterns - UI specific
232
- /page\.goto/,
233
- /page\.click/,
234
- /page\.fill/,
235
- /page\.screenshot/,
236
- /page\.waitForSelector/,
237
- /page\.locator/,
238
- /page\.getByRole/,
239
- // Cypress specific patterns
240
- /cy\.visit/,
241
- /cy\.get/,
242
- /cy\.click/,
243
- /cy\.type/,
244
- /cy\.should/,
245
- /cy\.wait/,
246
- /cy\.screenshot/,
247
- /cy\.viewport/,
248
- // WebDriverIO specific patterns
249
- /browser\.url/,
250
- /browser\.click/,
251
- /browser\.setValue/,
252
- /\$\(['"][#.]/,
253
- /\$\$\(['"][#.]/, // CSS/XPath selectors
254
- // Playwright specific
255
- /expect.*toBeVisible/,
256
- /expect.*toHaveText/,
257
- /expect.*toBeEnabled/,
258
- /locator\(/,
259
- /getByText\(/,
260
- /getByRole\(/,
261
- /getByTestId\(/,
262
- // DOM queries in test context
263
- /findElement/,
264
- /querySelector.*\)\.click/,
265
- /getElementById.*\)\.click/,
266
- // Test descriptions clearly indicating UI
267
- /describe.*['"`].*UI/,
268
- /describe.*['"`].*Web/,
269
- /describe.*['"`].*E2E/,
270
- /describe.*['"`].*Browser/,
271
- /describe.*['"`].*Selenium/,
272
- /it.*['"`].*(click|type|navigate|visit|see).*element/,
273
- /it.*['"`].*(open|load).*page/,
274
- /it.*['"`].*browser/,
275
- ],
276
- backendRegex: [
277
- /require\(['"]express['"]\)/,
278
- /require\(['"]fastify['"]\)/,
279
- /require\(['"]supertest['"]\)/,
280
- /request\(app\)/,
281
- /mongoose/,
282
- /sequelize/,
283
- /prisma/,
284
- /knex/,
285
- /app\.get\(/,
286
- /app\.post\(/,
287
- /server\./,
288
- /\.connect\(/,
289
- /\.query\(/,
290
- ],
291
- excludeRegex: [
292
- /\.unit\./,
293
- /\.mock\./,
294
- /jest\.mock/,
295
- /sinon/,
296
- /describe.*['"`]Unit/,
297
- /describe.*['"`]Mock/,
298
- ],
299
- },
300
- python: {
301
- extensions: [".py"],
302
- namePatterns: [
303
- /^test_.*\.py$/,
304
- /_test\.py$/,
305
- /test.*ui.*\.py$/,
306
- /test.*web.*\.py$/,
307
- /test.*e2e.*\.py$/,
308
- /test.*integration.*\.py$/,
309
- ],
310
- contentRegex: [
311
- /import\s+pytest/,
312
- /@pytest\.mark/,
313
- /def\s+test_/,
314
- /\bpytest\./,
315
- /import\s+unittest/,
316
- /class.*TestCase/,
317
- ],
318
- uiDriverRegex: [
319
- /import\s+selenium/,
320
- /from\s+selenium/,
321
- /import\s+playwright/,
322
- /from\s+playwright/,
323
- /import\s+appium/,
324
- /from\s+appium/,
325
- /import\s+splinter/,
326
- /from\s+splinter/,
327
- /driver\s*=\s*webdriver\./,
328
- /webdriver\.Chrome/,
329
- /webdriver\.Firefox/,
330
- ],
331
- uiIndicatorRegex: [
332
- // Selenium patterns without imports
333
- /\.find_element/,
334
- /\.click\(/,
335
- /\.send_keys/,
336
- /\.get\(/,
337
- /\.screenshot/,
338
- /\.execute_script/,
339
- /\.switch_to/,
340
- /By\.ID/,
341
- /By\.CLASS_NAME/,
342
- /By\.XPATH/,
343
- // Playwright patterns
344
- /page\.goto/,
345
- /page\.click/,
346
- /page\.fill/,
347
- /page\.screenshot/,
348
- /expect.*to_be_visible/,
349
- /expect.*to_have_text/,
350
- // Generic UI patterns
351
- /WebDriverWait/,
352
- /expected_conditions/,
353
- /ActionChains/,
354
- /@pytest\.mark\.ui/,
355
- /@pytest\.mark\.web/,
356
- /@pytest\.mark\.e2e/,
357
- // Page object patterns
358
- /BasePage/,
359
- /PageObject/,
360
- /WebPage/,
361
- // BDD step patterns
362
- /def\s+.*_(open|visit|navigate|click|type|see|verify)/,
363
- ],
364
- backendRegex: [
365
- /import\s+flask/,
366
- /from\s+flask/,
367
- /import\s+fastapi/,
368
- /from\s+fastapi/,
369
- /import\s+django/,
370
- /from\s+django/,
371
- /sqlalchemy/,
372
- /requests\.get/,
373
- /requests\.post/,
374
- /TestClient/,
375
- /@pytest\.mark\.django_db/,
376
- /django\.test/,
377
- ],
378
- excludeRegex: [
379
- /unittest\.mock/,
380
- /from\s+unittest\.mock/,
381
- /mock\.patch/,
382
- /@pytest\.mark\.unit/,
383
- /@mock\./,
384
- ],
385
- },
386
- ruby: {
387
- extensions: [".rb"],
388
- namePatterns: [
389
- /_spec\.rb$/,
390
- /_test\.rb$/,
391
- /.*ui.*_spec\.rb$/,
392
- /.*web.*_spec\.rb$/,
393
- /.*e2e.*_spec\.rb$/,
394
- ],
395
- contentRegex: [
396
- /\bdescribe\s/,
397
- /\bit\s/,
398
- /require\s+['"]rspec/,
399
- /require\s+['"]minitest/,
400
- /RSpec\.describe/,
401
- ],
402
- uiDriverRegex: [
403
- /require\s+['"]selenium-webdriver['"]/,
404
- /require\s+['"]capybara['"]/,
405
- /require\s+['"]appium_lib['"]/,
406
- /require\s+['"]watir['"]/,
407
- /Selenium::WebDriver/,
408
- /Capybara\./,
409
- ],
410
- uiIndicatorRegex: [
411
- // Capybara without explicit require
412
- /visit\s/,
413
- /click_button/,
414
- /click_link/,
415
- /fill_in/,
416
- /find\(['"]/,
417
- /has_content/,
418
- /page\./,
419
- /current_path/,
420
- // Selenium patterns
421
- /\.find_element/,
422
- /\.click/,
423
- /\.send_keys/,
424
- // Generic UI patterns
425
- /screenshot/,
426
- /driver\./,
427
- /browser\./,
428
- /feature\s+['"]/,
429
- /scenario\s+['"]/,
430
- /expect.*to\s+have_content/,
431
- /expect.*to\s+have_selector/,
432
- ],
433
- backendRegex: [
434
- /require\s+['"]sinatra['"]/,
435
- /require\s+['"]rails['"]/,
436
- /ActiveRecord/,
437
- /DatabaseCleaner/,
438
- /FactoryBot/,
439
- ],
440
- excludeRegex: [
441
- /double\(/,
442
- /instance_double/,
443
- /class_double/,
444
- /allow\(.*\)\.to\s+receive/,
445
- /mock/i,
446
- ],
447
- },
448
- };
449
- export const EXCLUDED_DIRS = new Set([
450
- "node_modules",
451
- ".venv",
452
- "venv",
453
- "__pycache__",
454
- "site-packages",
455
- "dist",
456
- "build",
457
- ".git",
458
- ".mypy_cache",
459
- ".pytest_cache",
460
- ".tox",
461
- ".idea",
462
- ".vscode",
463
- "coverage",
464
- ".nyc_output",
465
- "target",
466
- "bin",
467
- "obj",
468
- "packages",
469
- ".nuget",
470
- ]);
471
- export const backendIndicators = [
472
- /import\s+requests/,
473
- /requests\.(get|post|put|delete|patch)/,
474
- /@pytest\.mark\.(api|backend|integration)/,
475
- /BASE_URL\s*=/,
476
- /\.status_code/,
477
- /\.json\(\)/,
478
- /TestClient/,
479
- /Bearer\s+/,
480
- /Authorization.*Bearer/,
481
- ];
482
- export const strongUIIndicators = [
483
- // Browser automation with specific context
484
- /(driver|browser|page)\.(click|type|fill|screenshot|wait)/,
485
- /webdriver\.(Chrome|Firefox|Safari|Edge)/,
486
- /(selenium|playwright|puppeteer|cypress).*import/,
487
- // CSS/XPath selectors
488
- /By\.(ID|CLASS_NAME|XPATH|CSS_SELECTOR)/,
489
- /\$\(['"#[.][^'"]*['"]\)/, // $(".class") or $("#id")
490
- // Page Object Model
491
- /class.*Page.*:/,
492
- /class.*PageObject/,
493
- // UI test markers
494
- /@(ui|web|e2e|browser)_?test/,
495
- /@pytest\.mark\.(ui|web|e2e|browser)/,
496
- // Browser navigation
497
- /\.goto\s*\(['"]https?:/,
498
- /\.visit\s*\(['"]https?:/,
499
- /\.navigate\(\)\.to\(/,
500
- ];
@@ -1,10 +0,0 @@
1
- import { SDKSupportedLanguage, SDKSupportedTestingFrameworkEnum } from "../sdk-utils/common/types.js";
2
- export interface ListTestFilesOptions {
3
- language: SDKSupportedLanguage;
4
- framework?: SDKSupportedTestingFrameworkEnum;
5
- baseDir: string;
6
- strictMode?: boolean;
7
- }
8
- export declare function listTestFiles(options: ListTestFilesOptions): Promise<string[]>;
9
- export declare function listUITestFilesStrict(options: Omit<ListTestFilesOptions, "strictMode">): Promise<string[]>;
10
- export declare function listUITestFilesRelaxed(options: Omit<ListTestFilesOptions, "strictMode">): Promise<string[]>;
@@ -1,194 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import logger from "../../logger.js";
4
- import { EXCLUDED_DIRS, TEST_FILE_DETECTION, backendIndicators, strongUIIndicators, } from "../percy-snapshot-utils/constants.js";
5
- async function walkDir(dir, extensions) {
6
- const result = [];
7
- try {
8
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
9
- for (const entry of entries) {
10
- const fullPath = path.join(dir, entry.name);
11
- if (entry.isDirectory()) {
12
- if (!EXCLUDED_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
13
- result.push(...(await walkDir(fullPath, extensions)));
14
- }
15
- }
16
- else if (extensions.some((ext) => entry.name.endsWith(ext))) {
17
- result.push(fullPath);
18
- }
19
- }
20
- }
21
- catch {
22
- logger.error(`Failed to read directory: ${dir}`);
23
- }
24
- return result;
25
- }
26
- async function fileContainsRegex(filePath, regexes) {
27
- if (!regexes.length)
28
- return false;
29
- try {
30
- const content = await fs.promises.readFile(filePath, "utf8");
31
- return regexes.some((re) => re.test(content));
32
- }
33
- catch {
34
- logger.warn(`Failed to read file: ${filePath}`);
35
- return false;
36
- }
37
- }
38
- async function batchRegexCheck(filePath, regexGroups) {
39
- try {
40
- const content = await fs.promises.readFile(filePath, "utf8");
41
- return regexGroups.map((regexes) => regexes.length > 0 ? regexes.some((re) => re.test(content)) : false);
42
- }
43
- catch {
44
- logger.warn(`Failed to read file: ${filePath}`);
45
- return regexGroups.map(() => false);
46
- }
47
- }
48
- async function isLikelyUITest(filePath) {
49
- try {
50
- const content = await fs.promises.readFile(filePath, "utf8");
51
- if (backendIndicators.some((pattern) => pattern.test(content))) {
52
- return false;
53
- }
54
- return strongUIIndicators.some((pattern) => pattern.test(content));
55
- }
56
- catch {
57
- return false;
58
- }
59
- }
60
- function getFileScore(fileName, config) {
61
- let score = 0;
62
- // Higher score for explicit UI test naming
63
- if (/ui|web|e2e|integration|functional/i.test(fileName))
64
- score += 3;
65
- if (config.namePatterns.some((pattern) => pattern.test(fileName)))
66
- score += 2;
67
- return score;
68
- }
69
- export async function listTestFiles(options) {
70
- const { language, framework, baseDir, strictMode = false } = options;
71
- const config = TEST_FILE_DETECTION[language];
72
- if (!config) {
73
- logger.error(`Unsupported language: ${language}`);
74
- return [];
75
- }
76
- // Step 1: Collect all files with matching extensions
77
- let files = [];
78
- try {
79
- files = await walkDir(baseDir, config.extensions);
80
- }
81
- catch {
82
- return [];
83
- }
84
- if (files.length === 0) {
85
- throw new Error("No files found with the specified extensions");
86
- }
87
- const candidateFiles = new Map();
88
- // Step 2: Fast name-based identification with scoring
89
- for (const file of files) {
90
- const fileName = path.basename(file);
91
- const score = getFileScore(fileName, config);
92
- if (config.namePatterns.some((pattern) => pattern.test(fileName))) {
93
- candidateFiles.set(file, score);
94
- logger.debug(`File matched by name pattern: ${file} (score: ${score})`);
95
- }
96
- }
97
- // Step 3: Content-based test detection for remaining files
98
- const remainingFiles = files.filter((file) => !candidateFiles.has(file));
99
- const contentCheckPromises = remainingFiles.map(async (file) => {
100
- const hasTestContent = await fileContainsRegex(file, config.contentRegex);
101
- if (hasTestContent) {
102
- const fileName = path.basename(file);
103
- const score = getFileScore(fileName, config);
104
- candidateFiles.set(file, score);
105
- logger.debug(`File matched by content regex: ${file} (score: ${score})`);
106
- }
107
- });
108
- await Promise.all(contentCheckPromises);
109
- // Step 4: Handle SpecFlow .feature files for C# + SpecFlow
110
- if (language === "csharp" && framework === "specflow") {
111
- try {
112
- const featureFiles = await walkDir(baseDir, [".feature"]);
113
- featureFiles.forEach((file) => candidateFiles.set(file, 2));
114
- logger.info(`Added ${featureFiles.length} SpecFlow .feature files`);
115
- }
116
- catch {
117
- logger.warn(`Failed to collect SpecFlow .feature files from baseDir: ${baseDir}`);
118
- }
119
- }
120
- if (candidateFiles.size === 0) {
121
- logger.info("No test files found matching patterns");
122
- return [];
123
- }
124
- // Step 6: UI Detection with fallback patterns
125
- const uiFiles = [];
126
- const filesToCheck = Array.from(candidateFiles.keys());
127
- // Batch process UI detection for better performance
128
- const batchSize = 10;
129
- for (let i = 0; i < filesToCheck.length; i += batchSize) {
130
- const batch = filesToCheck.slice(i, i + batchSize);
131
- const batchPromises = batch.map(async (file) => {
132
- // First, use the new precise UI detection
133
- const isUITest = await isLikelyUITest(file);
134
- if (isUITest) {
135
- logger.debug(`File included - strong UI indicators: ${file}`);
136
- return file;
137
- }
138
- // If not clearly UI, run the traditional checks
139
- const [hasExplicitUI, hasUIIndicators, hasBackend, shouldExclude] = await batchRegexCheck(file, [
140
- config.uiDriverRegex,
141
- config.uiIndicatorRegex,
142
- config.backendRegex,
143
- config.excludeRegex || [],
144
- ]);
145
- // Skip if explicitly excluded (mocks, unit tests, etc.)
146
- if (shouldExclude) {
147
- logger.debug(`File excluded by exclude regex: ${file}`);
148
- return null;
149
- }
150
- // Skip backend tests in any mode
151
- if (hasBackend) {
152
- logger.debug(`File excluded as backend test: ${file}`);
153
- return null;
154
- }
155
- // Include if has explicit UI drivers
156
- if (hasExplicitUI) {
157
- logger.debug(`File included - explicit UI drivers: ${file}`);
158
- return file;
159
- }
160
- // Include if has UI indicators (for cases where drivers aren't explicitly imported)
161
- if (hasUIIndicators) {
162
- logger.debug(`File included - UI indicators: ${file}`);
163
- return file;
164
- }
165
- // In non-strict mode, include high-scoring test files even without explicit UI patterns
166
- if (!strictMode) {
167
- const score = candidateFiles.get(file) || 0;
168
- if (score >= 3) {
169
- // High confidence UI test based on naming
170
- logger.debug(`File included - high confidence score: ${file} (score: ${score})`);
171
- return file;
172
- }
173
- }
174
- logger.debug(`File excluded - no UI patterns detected: ${file}`);
175
- return null;
176
- });
177
- const batchResults = await Promise.all(batchPromises);
178
- uiFiles.push(...batchResults.filter((file) => file !== null));
179
- }
180
- // Step 7: Sort by score (higher confidence files first)
181
- uiFiles.sort((a, b) => {
182
- const scoreA = candidateFiles.get(a) || 0;
183
- const scoreB = candidateFiles.get(b) || 0;
184
- return scoreB - scoreA;
185
- });
186
- logger.info(`Returning ${uiFiles.length} UI test files from ${candidateFiles.size} total test files`);
187
- return uiFiles;
188
- }
189
- export async function listUITestFilesStrict(options) {
190
- return listTestFiles({ ...options, strictMode: true });
191
- }
192
- export async function listUITestFilesRelaxed(options) {
193
- return listTestFiles({ ...options, strictMode: false });
194
- }