@browserstack/mcp-server 1.2.3 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -2
- package/dist/lib/device-cache.js +20 -17
- package/dist/lib/inmemory-store.d.ts +1 -0
- package/dist/lib/inmemory-store.js +1 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +27 -0
- package/dist/server-factory.js +6 -0
- package/dist/tools/add-percy-snapshots.d.ts +5 -0
- package/dist/tools/add-percy-snapshots.js +17 -0
- package/dist/tools/appautomate-utils/appium-sdk/config-generator.d.ts +1 -0
- package/dist/tools/appautomate-utils/appium-sdk/config-generator.js +50 -0
- package/dist/tools/appautomate-utils/appium-sdk/constants.d.ts +23 -0
- package/dist/tools/appautomate-utils/appium-sdk/constants.js +43 -0
- package/dist/tools/appautomate-utils/appium-sdk/formatter.d.ts +8 -0
- package/dist/tools/appautomate-utils/appium-sdk/formatter.js +59 -0
- package/dist/tools/appautomate-utils/appium-sdk/handler.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/handler.js +52 -0
- package/dist/tools/appautomate-utils/appium-sdk/index.d.ts +7 -0
- package/dist/tools/appautomate-utils/appium-sdk/index.js +8 -0
- package/dist/tools/appautomate-utils/appium-sdk/instructions.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/instructions.js +47 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.d.ts +2 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.js +78 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/java.d.ts +8 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/java.js +87 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.js +194 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/python.d.ts +3 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/python.js +76 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.d.ts +2 -0
- package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.js +85 -0
- package/dist/tools/appautomate-utils/appium-sdk/types.d.ts +57 -0
- package/dist/tools/appautomate-utils/appium-sdk/types.js +54 -0
- package/dist/tools/appautomate-utils/appium-sdk/utils.d.ts +17 -0
- package/dist/tools/appautomate-utils/appium-sdk/utils.js +64 -0
- package/dist/tools/appautomate-utils/{appautomate.d.ts → native-execution/appautomate.d.ts} +1 -1
- package/dist/tools/appautomate-utils/{appautomate.js → native-execution/appautomate.js} +2 -2
- package/dist/tools/appautomate-utils/native-execution/constants.d.ts +10 -0
- package/dist/tools/appautomate-utils/native-execution/constants.js +36 -0
- package/dist/tools/appautomate-utils/native-execution/types.d.ts +19 -0
- package/dist/tools/appautomate-utils/{types.js → native-execution/types.js} +5 -1
- package/dist/tools/appautomate.js +25 -40
- package/dist/tools/bstack-sdk.d.ts +2 -15
- package/dist/tools/bstack-sdk.js +10 -119
- package/dist/tools/build-insights.d.ts +7 -0
- package/dist/tools/build-insights.js +67 -0
- package/dist/tools/list-test-files.d.ts +2 -0
- package/dist/tools/list-test-files.js +36 -0
- package/dist/tools/percy-sdk.d.ts +4 -0
- package/dist/tools/percy-sdk.js +71 -0
- package/dist/tools/percy-snapshot-utils/constants.d.ts +16 -0
- package/dist/tools/percy-snapshot-utils/constants.js +500 -0
- package/dist/tools/percy-snapshot-utils/detect-test-files.d.ts +10 -0
- package/dist/tools/percy-snapshot-utils/detect-test-files.js +175 -0
- package/dist/tools/percy-snapshot-utils/types.d.ts +15 -0
- package/dist/tools/percy-snapshot-utils/utils.d.ts +4 -0
- package/dist/tools/percy-snapshot-utils/utils.js +30 -0
- package/dist/tools/rca-agent-utils/constants.d.ts +13 -0
- package/dist/tools/rca-agent-utils/constants.js +24 -0
- package/dist/tools/rca-agent-utils/format-rca.d.ts +1 -0
- package/dist/tools/rca-agent-utils/format-rca.js +37 -0
- package/dist/tools/rca-agent-utils/get-build-id.d.ts +1 -0
- package/dist/tools/rca-agent-utils/get-build-id.js +18 -0
- package/dist/tools/rca-agent-utils/get-failed-test-id.d.ts +2 -0
- package/dist/tools/rca-agent-utils/get-failed-test-id.js +69 -0
- package/dist/tools/rca-agent-utils/rca-data.d.ts +9 -0
- package/dist/tools/rca-agent-utils/rca-data.js +196 -0
- package/dist/tools/rca-agent-utils/types.d.ts +48 -0
- package/dist/tools/rca-agent-utils/types.js +20 -0
- package/dist/tools/rca-agent.d.ts +14 -0
- package/dist/tools/rca-agent.js +119 -0
- package/dist/tools/review-agent-utils/build-counts.d.ts +7 -0
- package/dist/tools/review-agent-utils/build-counts.js +44 -0
- package/dist/tools/review-agent-utils/percy-approve-reject.d.ts +6 -0
- package/dist/tools/review-agent-utils/percy-approve-reject.js +39 -0
- package/dist/tools/review-agent-utils/percy-diffs.d.ts +9 -0
- package/dist/tools/review-agent-utils/percy-diffs.js +35 -0
- package/dist/tools/review-agent-utils/percy-snapshots.d.ts +11 -0
- package/dist/tools/review-agent-utils/percy-snapshots.js +58 -0
- package/dist/tools/review-agent.d.ts +5 -0
- package/dist/tools/review-agent.js +56 -0
- package/dist/tools/run-percy-scan.d.ts +8 -0
- package/dist/tools/run-percy-scan.js +37 -0
- package/dist/tools/sdk-utils/{commands.d.ts → bstack/commands.d.ts} +1 -1
- package/dist/tools/sdk-utils/bstack/commands.js +88 -0
- package/dist/tools/sdk-utils/bstack/configUtils.d.ts +4 -0
- package/dist/tools/sdk-utils/bstack/configUtils.js +66 -0
- package/dist/tools/sdk-utils/bstack/constants.d.ts +58 -0
- package/dist/tools/sdk-utils/{constants.js → bstack/constants.js} +117 -78
- package/dist/tools/sdk-utils/{constants.d.ts → bstack/frameworks.d.ts} +1 -1
- package/dist/tools/sdk-utils/bstack/frameworks.js +57 -0
- package/dist/tools/sdk-utils/bstack/index.d.ts +4 -0
- package/dist/tools/sdk-utils/bstack/index.js +5 -0
- package/dist/tools/sdk-utils/bstack/sdkHandler.d.ts +4 -0
- package/dist/tools/sdk-utils/bstack/sdkHandler.js +74 -0
- package/dist/tools/sdk-utils/common/constants.d.ts +10 -0
- package/dist/tools/sdk-utils/common/constants.js +86 -0
- package/dist/tools/sdk-utils/common/formatUtils.d.ts +5 -0
- package/dist/tools/sdk-utils/common/formatUtils.js +27 -0
- package/dist/tools/sdk-utils/common/index.d.ts +3 -0
- package/dist/tools/sdk-utils/common/index.js +4 -0
- package/dist/tools/sdk-utils/common/instructionUtils.d.ts +8 -0
- package/dist/tools/sdk-utils/common/instructionUtils.js +20 -0
- package/dist/tools/sdk-utils/common/schema.d.ts +73 -0
- package/dist/tools/sdk-utils/common/schema.js +51 -0
- package/dist/tools/sdk-utils/common/types.d.ts +66 -0
- package/dist/tools/sdk-utils/{types.js → common/types.js} +15 -2
- package/dist/tools/sdk-utils/common/utils.d.ts +25 -0
- package/dist/tools/sdk-utils/common/utils.js +90 -0
- package/dist/tools/sdk-utils/handler.d.ts +4 -0
- package/dist/tools/sdk-utils/handler.js +119 -0
- package/dist/tools/sdk-utils/percy-automate/constants.d.ts +11 -0
- package/dist/tools/sdk-utils/percy-automate/constants.js +338 -0
- package/dist/tools/sdk-utils/percy-automate/frameworks.d.ts +8 -0
- package/dist/tools/sdk-utils/percy-automate/frameworks.js +50 -0
- package/dist/tools/sdk-utils/percy-automate/handler.d.ts +3 -0
- package/dist/tools/sdk-utils/percy-automate/handler.js +30 -0
- package/dist/tools/sdk-utils/percy-automate/index.d.ts +1 -0
- package/dist/tools/sdk-utils/percy-automate/index.js +2 -0
- package/dist/tools/sdk-utils/percy-automate/types.d.ts +13 -0
- package/dist/tools/sdk-utils/percy-automate/types.js +1 -0
- package/dist/tools/sdk-utils/percy-bstack/constants.d.ts +4 -0
- package/dist/tools/sdk-utils/{percy → percy-bstack}/constants.js +13 -39
- package/dist/tools/sdk-utils/percy-bstack/frameworks.d.ts +2 -0
- package/dist/tools/sdk-utils/percy-bstack/frameworks.js +27 -0
- package/dist/tools/sdk-utils/percy-bstack/handler.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-bstack/handler.js +99 -0
- package/dist/tools/sdk-utils/percy-bstack/index.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-bstack/index.js +4 -0
- package/dist/tools/sdk-utils/percy-bstack/instructions.d.ts +7 -0
- package/dist/tools/sdk-utils/{percy → percy-bstack}/instructions.js +5 -9
- package/dist/tools/sdk-utils/percy-bstack/types.d.ts +13 -0
- package/dist/tools/sdk-utils/percy-bstack/types.js +5 -0
- package/dist/tools/sdk-utils/percy-web/constants.d.ts +41 -0
- package/dist/tools/sdk-utils/percy-web/constants.js +883 -0
- package/dist/tools/sdk-utils/percy-web/fetchPercyToken.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-web/fetchPercyToken.js +32 -0
- package/dist/tools/sdk-utils/percy-web/frameworks.d.ts +7 -0
- package/dist/tools/sdk-utils/percy-web/frameworks.js +103 -0
- package/dist/tools/sdk-utils/percy-web/handler.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-web/handler.js +27 -0
- package/dist/tools/sdk-utils/percy-web/index.d.ts +4 -0
- package/dist/tools/sdk-utils/percy-web/index.js +4 -0
- package/dist/tools/sdk-utils/percy-web/types.d.ts +12 -0
- package/dist/tools/sdk-utils/percy-web/types.js +1 -0
- package/dist/tools/testmanagement-utils/create-testrun.d.ts +4 -4
- package/dist/tools/testmanagement-utils/update-testrun.d.ts +4 -4
- package/package.json +2 -1
- package/dist/tools/appautomate-utils/types.d.ts +0 -5
- package/dist/tools/sdk-utils/commands.js +0 -65
- package/dist/tools/sdk-utils/instructions.d.ts +0 -6
- package/dist/tools/sdk-utils/instructions.js +0 -99
- package/dist/tools/sdk-utils/percy/constants.d.ts +0 -3
- package/dist/tools/sdk-utils/percy/instructions.d.ts +0 -10
- package/dist/tools/sdk-utils/percy/types.d.ts +0 -5
- package/dist/tools/sdk-utils/types.d.ts +0 -40
- /package/dist/tools/{sdk-utils/percy → percy-snapshot-utils}/types.js +0 -0
|
@@ -0,0 +1,500 @@
|
|
|
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
|
+
];
|
|
@@ -0,0 +1,10 @@
|
|
|
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[]>;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { EXCLUDED_DIRS, TEST_FILE_DETECTION, backendIndicators, strongUIIndicators, } from "../percy-snapshot-utils/constants.js";
|
|
4
|
+
import logger from "../../logger.js";
|
|
5
|
+
async function walkDir(dir, extensions, depth = 6) {
|
|
6
|
+
const result = [];
|
|
7
|
+
if (depth < 0)
|
|
8
|
+
return result;
|
|
9
|
+
try {
|
|
10
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
const fullPath = path.join(dir, entry.name);
|
|
13
|
+
if (entry.isDirectory()) {
|
|
14
|
+
if (!EXCLUDED_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
15
|
+
result.push(...(await walkDir(fullPath, extensions, depth - 1)));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else if (extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
19
|
+
result.push(fullPath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
logger.info("Failed to read user directory");
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
async function fileContainsRegex(filePath, regexes) {
|
|
29
|
+
if (!regexes.length)
|
|
30
|
+
return false;
|
|
31
|
+
try {
|
|
32
|
+
const content = await fs.promises.readFile(filePath, "utf8");
|
|
33
|
+
return regexes.some((re) => re.test(content));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function batchRegexCheck(filePath, regexGroups) {
|
|
40
|
+
try {
|
|
41
|
+
const content = await fs.promises.readFile(filePath, "utf8");
|
|
42
|
+
return regexGroups.map((regexes) => regexes.length > 0 ? regexes.some((re) => re.test(content)) : false);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
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
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
// Step 1: Collect all files with matching extensions
|
|
76
|
+
let files = [];
|
|
77
|
+
try {
|
|
78
|
+
files = await walkDir(baseDir, config.extensions, 6);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
if (files.length === 0) {
|
|
84
|
+
throw new Error("No files found with the specified extensions");
|
|
85
|
+
}
|
|
86
|
+
const candidateFiles = new Map();
|
|
87
|
+
// Step 2: Fast name-based identification with scoring
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
const fileName = path.basename(file);
|
|
90
|
+
const score = getFileScore(fileName, config);
|
|
91
|
+
if (config.namePatterns.some((pattern) => pattern.test(fileName))) {
|
|
92
|
+
candidateFiles.set(file, score);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Step 3: Content-based test detection for remaining files
|
|
96
|
+
const remainingFiles = files.filter((file) => !candidateFiles.has(file));
|
|
97
|
+
const contentCheckPromises = remainingFiles.map(async (file) => {
|
|
98
|
+
const hasTestContent = await fileContainsRegex(file, config.contentRegex);
|
|
99
|
+
if (hasTestContent) {
|
|
100
|
+
const fileName = path.basename(file);
|
|
101
|
+
const score = getFileScore(fileName, config);
|
|
102
|
+
candidateFiles.set(file, score);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
await Promise.all(contentCheckPromises);
|
|
106
|
+
// Step 4: Handle SpecFlow .feature files for C# + SpecFlow
|
|
107
|
+
if (language === "csharp" && framework === "specflow") {
|
|
108
|
+
try {
|
|
109
|
+
const featureFiles = await walkDir(baseDir, [".feature"], 6);
|
|
110
|
+
featureFiles.forEach((file) => candidateFiles.set(file, 2));
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// ignore
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (candidateFiles.size === 0) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
// Step 6: UI Detection with fallback patterns
|
|
120
|
+
const uiFiles = [];
|
|
121
|
+
const filesToCheck = Array.from(candidateFiles.keys());
|
|
122
|
+
// Batch process UI detection for better performance
|
|
123
|
+
const batchSize = 10;
|
|
124
|
+
for (let i = 0; i < filesToCheck.length; i += batchSize) {
|
|
125
|
+
const batch = filesToCheck.slice(i, i + batchSize);
|
|
126
|
+
const batchPromises = batch.map(async (file) => {
|
|
127
|
+
// First, use the new precise UI detection
|
|
128
|
+
const isUITest = await isLikelyUITest(file);
|
|
129
|
+
if (isUITest) {
|
|
130
|
+
return file;
|
|
131
|
+
}
|
|
132
|
+
// If not clearly UI, run the traditional checks
|
|
133
|
+
const [hasExplicitUI, hasUIIndicators, hasBackend, shouldExclude] = await batchRegexCheck(file, [
|
|
134
|
+
config.uiDriverRegex,
|
|
135
|
+
config.uiIndicatorRegex,
|
|
136
|
+
config.backendRegex,
|
|
137
|
+
config.excludeRegex || [],
|
|
138
|
+
]);
|
|
139
|
+
if (shouldExclude) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
if (hasBackend) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
if (hasExplicitUI) {
|
|
146
|
+
return file;
|
|
147
|
+
}
|
|
148
|
+
if (hasUIIndicators) {
|
|
149
|
+
return file;
|
|
150
|
+
}
|
|
151
|
+
if (!strictMode) {
|
|
152
|
+
const score = candidateFiles.get(file) || 0;
|
|
153
|
+
if (score >= 3) {
|
|
154
|
+
return file;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
});
|
|
159
|
+
const batchResults = await Promise.all(batchPromises);
|
|
160
|
+
uiFiles.push(...batchResults.filter((file) => file !== null));
|
|
161
|
+
}
|
|
162
|
+
// Step 7: Sort by score (higher confidence files first)
|
|
163
|
+
uiFiles.sort((a, b) => {
|
|
164
|
+
const scoreA = candidateFiles.get(a) || 0;
|
|
165
|
+
const scoreB = candidateFiles.get(b) || 0;
|
|
166
|
+
return scoreB - scoreA;
|
|
167
|
+
});
|
|
168
|
+
return uiFiles;
|
|
169
|
+
}
|
|
170
|
+
export async function listUITestFilesStrict(options) {
|
|
171
|
+
return listTestFiles({ ...options, strictMode: true });
|
|
172
|
+
}
|
|
173
|
+
export async function listUITestFilesRelaxed(options) {
|
|
174
|
+
return listTestFiles({ ...options, strictMode: false });
|
|
175
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SDKSupportedTestingFrameworkEnum, SDKSupportedLanguageEnum } from "../sdk-utils/common/types.js";
|
|
2
|
+
export type ListTestFilesParams = {
|
|
3
|
+
dirs: string[];
|
|
4
|
+
language: SDKSupportedLanguageEnum;
|
|
5
|
+
framework?: SDKSupportedTestingFrameworkEnum;
|
|
6
|
+
};
|
|
7
|
+
export interface DetectionConfig {
|
|
8
|
+
extensions: string[];
|
|
9
|
+
namePatterns: RegExp[];
|
|
10
|
+
contentRegex: RegExp[];
|
|
11
|
+
uiDriverRegex: RegExp[];
|
|
12
|
+
uiIndicatorRegex: RegExp[];
|
|
13
|
+
backendRegex: RegExp[];
|
|
14
|
+
excludeRegex?: RegExp[];
|
|
15
|
+
}
|