ado-sync 0.1.24 → 0.1.27
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 +240 -678
- package/dist/azure/client.d.ts +3 -0
- package/dist/azure/client.js +6 -0
- package/dist/azure/client.js.map +1 -1
- package/dist/azure/test-cases.d.ts +8 -3
- package/dist/azure/test-cases.js +406 -25
- package/dist/azure/test-cases.js.map +1 -1
- package/dist/cli.js +51 -4
- package/dist/cli.js.map +1 -1
- package/dist/config.js +111 -5
- package/dist/config.js.map +1 -1
- package/dist/parsers/csharp.d.ts +30 -0
- package/dist/parsers/csharp.js +257 -0
- package/dist/parsers/csharp.js.map +1 -0
- package/dist/parsers/gherkin.d.ts +4 -1
- package/dist/parsers/gherkin.js +19 -4
- package/dist/parsers/gherkin.js.map +1 -1
- package/dist/parsers/java.d.ts +40 -0
- package/dist/parsers/java.js +329 -0
- package/dist/parsers/java.js.map +1 -0
- package/dist/parsers/javascript.d.ts +33 -0
- package/dist/parsers/javascript.js +261 -0
- package/dist/parsers/javascript.js.map +1 -0
- package/dist/parsers/markdown.d.ts +4 -1
- package/dist/parsers/markdown.js +5 -3
- package/dist/parsers/markdown.js.map +1 -1
- package/dist/parsers/python.d.ts +34 -0
- package/dist/parsers/python.js +305 -0
- package/dist/parsers/python.js.map +1 -0
- package/dist/parsers/shared.d.ts +18 -0
- package/dist/parsers/shared.js +40 -0
- package/dist/parsers/shared.js.map +1 -1
- package/dist/sync/engine.js +114 -5
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/publish-results.d.ts +49 -0
- package/dist/sync/publish-results.js +476 -0
- package/dist/sync/publish-results.js.map +1 -0
- package/dist/sync/writeback.d.ts +57 -1
- package/dist/sync/writeback.js +243 -0
- package/dist/sync/writeback.js.map +1 -1
- package/dist/types.d.ts +159 -2
- package/docs/advanced.md +350 -0
- package/docs/configuration.md +293 -0
- package/docs/publish-test-results.md +317 -0
- package/docs/spec-formats.md +595 -0
- package/package.json +1 -1
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
# Spec file formats
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Gherkin `.feature`
|
|
6
|
+
|
|
7
|
+
Set `local.type: "gherkin"`. Standard Gherkin syntax is supported:
|
|
8
|
+
|
|
9
|
+
- `Feature` / `Scenario` / `Scenario Outline` / `Background`
|
|
10
|
+
- `Given` / `When` / `Then` / `And` / `But`
|
|
11
|
+
- Feature-level and scenario-level tags
|
|
12
|
+
- `Scenario Outline` with `Examples` tables — creates a **single** parametrized Test Case in Azure, not one TC per row
|
|
13
|
+
- Inline data tables (synced as sub-steps or plain text — see [Format configuration](advanced.md#format-configuration))
|
|
14
|
+
|
|
15
|
+
```gherkin
|
|
16
|
+
Feature: Checkout
|
|
17
|
+
|
|
18
|
+
Background:
|
|
19
|
+
Given I am on the storefront
|
|
20
|
+
|
|
21
|
+
@smoke
|
|
22
|
+
@tc:1041
|
|
23
|
+
Scenario: Add item and complete checkout
|
|
24
|
+
Given I am logged in as "standard_user"
|
|
25
|
+
When I add "Sauce Labs Backpack" to the cart
|
|
26
|
+
And I proceed through checkout with name "Test User" and zip "12345"
|
|
27
|
+
Then I see the order confirmation page
|
|
28
|
+
|
|
29
|
+
@tc:1042
|
|
30
|
+
Scenario Outline: Checkout with different users
|
|
31
|
+
Given I am logged in as "<user>"
|
|
32
|
+
When I complete a checkout
|
|
33
|
+
Then the result is "<result>"
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
| user | result |
|
|
37
|
+
| standard_user | success |
|
|
38
|
+
| performance_glitch_user | success |
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Markdown `.md`
|
|
44
|
+
|
|
45
|
+
Set `local.type: "markdown"`. Each `### heading` is one test case. Scenarios are separated by `---`.
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
# My Feature Test Plan
|
|
49
|
+
|
|
50
|
+
## Test scenarios
|
|
51
|
+
|
|
52
|
+
### Login with valid credentials
|
|
53
|
+
@tc:1042 @smoke
|
|
54
|
+
|
|
55
|
+
Assumption: Fresh browser session.
|
|
56
|
+
|
|
57
|
+
Steps:
|
|
58
|
+
1. Navigate to https://example.com/login
|
|
59
|
+
2. Enter username "admin" and password "secret"
|
|
60
|
+
3. Click the Login button
|
|
61
|
+
|
|
62
|
+
Expected results:
|
|
63
|
+
- The dashboard page is shown
|
|
64
|
+
- The username appears in the top navigation
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### Login with invalid credentials
|
|
69
|
+
|
|
70
|
+
Steps:
|
|
71
|
+
1. Navigate to https://example.com/login
|
|
72
|
+
2. Enter username "wrong" and password "wrong"
|
|
73
|
+
3. Click the Login button
|
|
74
|
+
|
|
75
|
+
Expected results:
|
|
76
|
+
- An error message "Invalid credentials" is displayed
|
|
77
|
+
- The user remains on the login page
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Sections recognised (case-insensitive): `Steps:`, `Expected results:`. All other prose is captured as the test case description. Heading number prefixes (`### 1. Title` or `### Title`) are both supported.
|
|
83
|
+
|
|
84
|
+
### Playwright test-plan markdown
|
|
85
|
+
|
|
86
|
+
Markdown files generated by the Playwright MCP agent are fully supported. Set `local.type: "markdown"` and point `local.include` at the generated files.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## C# MSTest / NUnit `.cs`
|
|
91
|
+
|
|
92
|
+
Set `local.type: "csharp"`. Both **MSTest** and **NUnit** frameworks are supported. Each test method becomes one Test Case.
|
|
93
|
+
|
|
94
|
+
### Framework attribute mapping
|
|
95
|
+
|
|
96
|
+
| Concern | MSTest | NUnit |
|
|
97
|
+
|---------|--------|-------|
|
|
98
|
+
| Test marker | `[TestMethod]` | `[Test]` |
|
|
99
|
+
| Category / tag | `[TestCategory("name")]` | `[Category("name")]` |
|
|
100
|
+
| Custom property | `[TestProperty("key","val")]` | `[Property("key","val")]` |
|
|
101
|
+
| TC ID writeback | `[TestProperty("tc","ID")]` | `[Property("tc","ID")]` |
|
|
102
|
+
|
|
103
|
+
The framework is auto-detected per method — mixed files (e.g. a shared helper class) are handled correctly.
|
|
104
|
+
|
|
105
|
+
### Source mapping (both frameworks)
|
|
106
|
+
|
|
107
|
+
| C# source | Azure TC field |
|
|
108
|
+
|-----------|---------------|
|
|
109
|
+
| XML doc `<summary>` first line | TC **Title** |
|
|
110
|
+
| Numbered lines `N. text` in summary | TC **Steps** (action) |
|
|
111
|
+
| Numbered lines `N. Check: text` | TC **Steps** (expected result, when `useExpectedResult: true`) |
|
|
112
|
+
| `[TestCategory("…")]` / `[Category("…")]` | TC **Tags** (string literals and `const string` constants resolved) |
|
|
113
|
+
| `[TestProperty("tc","ID")]` / `[Property("tc","ID")]` | TC ID (written back after first push) |
|
|
114
|
+
| `Namespace.Class.MethodName` | `AutomatedTestName` (for TRX result linking) |
|
|
115
|
+
|
|
116
|
+
### MSTest example
|
|
117
|
+
|
|
118
|
+
```csharp
|
|
119
|
+
/// <summary>
|
|
120
|
+
/// Verify CoCounsel dialog opens on Edge
|
|
121
|
+
/// Test case: 1883058
|
|
122
|
+
/// 1. Sign in to Westlaw Edge
|
|
123
|
+
/// 2. Click CoCounsel link from page header
|
|
124
|
+
/// 3. Check: Verify CoCounsel dialog opens with correct title
|
|
125
|
+
/// 4. Check: Verify Close button is displayed
|
|
126
|
+
/// </summary>
|
|
127
|
+
[TestMethod]
|
|
128
|
+
[TestProperty("tc", "1883058")] // written back by ado-sync after first push
|
|
129
|
+
[TestCategory("EdgeAalp")]
|
|
130
|
+
[TestCategory("EdgeAalpSmoke")]
|
|
131
|
+
public void EdgeAalpAccessTest()
|
|
132
|
+
{
|
|
133
|
+
// ...
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### NUnit example
|
|
138
|
+
|
|
139
|
+
```csharp
|
|
140
|
+
/// <summary>
|
|
141
|
+
/// Verify login with valid credentials
|
|
142
|
+
/// 1. Navigate to the login page
|
|
143
|
+
/// 2. Enter username and password
|
|
144
|
+
/// 3. Click the Login button
|
|
145
|
+
/// 4. Check: Dashboard page is shown
|
|
146
|
+
/// 5. Check: Username appears in the top navigation
|
|
147
|
+
/// </summary>
|
|
148
|
+
[Test]
|
|
149
|
+
[Property("tc", "2001")] // written back by ado-sync after first push
|
|
150
|
+
[Category("Smoke")]
|
|
151
|
+
[Category("Authentication")]
|
|
152
|
+
public void LoginWithValidCredentials()
|
|
153
|
+
{
|
|
154
|
+
// ...
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Recommended config
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"local": {
|
|
163
|
+
"type": "csharp",
|
|
164
|
+
"include": ["**/RegressionTests/**/*.cs"],
|
|
165
|
+
"exclude": ["**/*BaseTest.cs", "**/*BaseFixture.cs", "**/*Helper.cs"]
|
|
166
|
+
},
|
|
167
|
+
"sync": {
|
|
168
|
+
"markAutomated": true,
|
|
169
|
+
"format": { "useExpectedResult": true }
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
With `useExpectedResult: true`, `Check:` lines go into the Expected Result column of each TC step. With `markAutomated: true`, the TC's Associated Automation is set to the fully-qualified method name (`Namespace.Class.Method`), enabling `publish-test-results` to link TRX run outcomes back to TCs.
|
|
175
|
+
|
|
176
|
+
### Notes
|
|
177
|
+
|
|
178
|
+
- **Constants** — ado-sync resolves `const string` declarations within the same file. Constants defined in a base class are not resolved; use string literals for reliable tagging.
|
|
179
|
+
- **`pull` is not supported** for C# files. Only `push` and `publish-test-results` apply.
|
|
180
|
+
- **Base classes / fixtures** — exclude them from `local.include` to avoid treating non-test methods as test cases.
|
|
181
|
+
- **NUnit `[TestCase]`** — parameterised data rows (`[TestCase(1, "foo")]`) are not expanded into separate TCs. Only the `[Test]` marker is treated as the test definition.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Java JUnit / TestNG `.java`
|
|
186
|
+
|
|
187
|
+
Set `local.type: "java"`. Supports **JUnit 4**, **JUnit 5**, and **TestNG** (including Selenium-based tests). Each `@Test`-annotated method becomes one Test Case.
|
|
188
|
+
|
|
189
|
+
### Framework attribute mapping
|
|
190
|
+
|
|
191
|
+
| Concern | JUnit 4 | JUnit 5 | TestNG |
|
|
192
|
+
|---------|---------|---------|--------|
|
|
193
|
+
| Test marker | `@Test` (`org.junit.Test`) | `@Test` (`org.junit.jupiter.api.Test`) | `@Test` (`org.testng.annotations.Test`) |
|
|
194
|
+
| Tag / category | `@Category(Smoke.class)` | `@Tag("smoke")` | `groups = {"smoke"}` in `@Test` |
|
|
195
|
+
| TC ID writeback | `// @tc:ID` above `@Test` | `@Tag("tc:ID")` above `@Test` | `// @tc:ID` above `@Test` |
|
|
196
|
+
|
|
197
|
+
The framework is auto-detected per file from import statements — no config required.
|
|
198
|
+
|
|
199
|
+
### Source mapping (all frameworks)
|
|
200
|
+
|
|
201
|
+
| Java source | Azure TC field |
|
|
202
|
+
|-------------|---------------|
|
|
203
|
+
| Javadoc `/** ... */` first non-numbered line | TC **Title** |
|
|
204
|
+
| Numbered lines `N. text` in Javadoc | TC **Steps** (action) |
|
|
205
|
+
| Numbered lines `N. Check: text` in Javadoc | TC **Steps** (expected result, when `useExpectedResult: true`) |
|
|
206
|
+
| `@Category`, `@Tag`, `groups` in `@Test` | TC **Tags** |
|
|
207
|
+
| `// @tc:ID` or `@Tag("tc:ID")` | TC ID (written back after first push) |
|
|
208
|
+
| `com.example.MyClass.myMethod` | `AutomatedTestName` (for JUnit XML result linking) |
|
|
209
|
+
|
|
210
|
+
### JUnit 5 example
|
|
211
|
+
|
|
212
|
+
```java
|
|
213
|
+
import org.junit.jupiter.api.Tag;
|
|
214
|
+
import org.junit.jupiter.api.Test;
|
|
215
|
+
|
|
216
|
+
class CheckoutTests {
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Add item and complete checkout
|
|
220
|
+
* 1. Sign in as standard_user
|
|
221
|
+
* 2. Add "Sauce Labs Backpack" to cart
|
|
222
|
+
* 3. Proceed through checkout
|
|
223
|
+
* 4. Check: Order confirmation page is shown
|
|
224
|
+
*/
|
|
225
|
+
@Tag("tc:1041") // written back by ado-sync after first push
|
|
226
|
+
@Tag("smoke")
|
|
227
|
+
@Test
|
|
228
|
+
void addItemAndCompleteCheckout() {
|
|
229
|
+
// ...
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### JUnit 4 example
|
|
235
|
+
|
|
236
|
+
```java
|
|
237
|
+
import org.junit.Test;
|
|
238
|
+
import org.junit.experimental.categories.Category;
|
|
239
|
+
|
|
240
|
+
public class LoginTests {
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Login with valid credentials
|
|
244
|
+
* 1. Navigate to the login page
|
|
245
|
+
* 2. Enter username and password
|
|
246
|
+
* 3. Check: Dashboard page is shown
|
|
247
|
+
*/
|
|
248
|
+
// @tc:1042 // written back by ado-sync after first push
|
|
249
|
+
@Test
|
|
250
|
+
@Category(Smoke.class)
|
|
251
|
+
public void loginWithValidCredentials() {
|
|
252
|
+
// ...
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### TestNG example
|
|
258
|
+
|
|
259
|
+
```java
|
|
260
|
+
import org.testng.annotations.Test;
|
|
261
|
+
|
|
262
|
+
public class SearchTests {
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Search returns relevant results
|
|
266
|
+
* 1. Open the search page
|
|
267
|
+
* 2. Enter "junit 5" in the search box
|
|
268
|
+
* 3. Check: Results list contains at least one entry
|
|
269
|
+
*/
|
|
270
|
+
// @tc:1043 // written back by ado-sync after first push
|
|
271
|
+
@Test(groups = {"regression", "search"})
|
|
272
|
+
public void searchReturnsRelevantResults() {
|
|
273
|
+
// ...
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Recommended config
|
|
279
|
+
|
|
280
|
+
```json
|
|
281
|
+
{
|
|
282
|
+
"local": {
|
|
283
|
+
"type": "java",
|
|
284
|
+
"include": ["**/src/test/**/*.java"],
|
|
285
|
+
"exclude": ["**/*BaseTest.java", "**/*Helper.java", "**/*Utils.java"]
|
|
286
|
+
},
|
|
287
|
+
"sync": {
|
|
288
|
+
"markAutomated": true
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Notes
|
|
294
|
+
|
|
295
|
+
- **`pull` is not supported** for Java files. Only `push` and `publish-test-results` apply.
|
|
296
|
+
- **Abstract base test classes** — exclude them from `local.include` to avoid treating base methods as test cases.
|
|
297
|
+
- **JUnit 5 `@Tag`** — the `org.junit.jupiter.api.Tag` import must be present or the file must already use Jupiter annotations; ado-sync adds the tag annotation but not the import if it's missing.
|
|
298
|
+
- **TestNG `groups`** — `groups = {"smoke", "regression"}` inside `@Test(...)` are extracted as TC tags.
|
|
299
|
+
- **`@ParameterizedTest` / `@DataProvider`** — parameterised data rows are not expanded into separate TCs; only the method definition is treated as the test case.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Python pytest `.py`
|
|
304
|
+
|
|
305
|
+
Set `local.type: "python"`. Each `def test_*` function — at module level or inside a class — becomes one Test Case. No extra dependencies required beyond `pytest` itself.
|
|
306
|
+
|
|
307
|
+
### Source mapping
|
|
308
|
+
|
|
309
|
+
| Python source | Azure TC field |
|
|
310
|
+
|---------------|---------------|
|
|
311
|
+
| Docstring first non-numbered line | TC **Title** |
|
|
312
|
+
| Numbered lines `N. text` in docstring | TC **Steps** (action) |
|
|
313
|
+
| Numbered lines `N. Check: text` in docstring | TC **Steps** (expected result, when `useExpectedResult: true`) |
|
|
314
|
+
| `@pytest.mark.<tag>` decorators | TC **Tags** (built-in pytest marks excluded) |
|
|
315
|
+
| `@pytest.mark.tc(ID)` | TC ID (written back after first push) |
|
|
316
|
+
| `module.path.ClassName.test_method` | `AutomatedTestName` (for JUnit XML result linking) |
|
|
317
|
+
|
|
318
|
+
### Example
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
import pytest
|
|
322
|
+
|
|
323
|
+
class TestCheckout:
|
|
324
|
+
|
|
325
|
+
@pytest.mark.tc(1041) # written back by ado-sync after first push
|
|
326
|
+
@pytest.mark.smoke
|
|
327
|
+
def test_add_item_and_complete_checkout(self):
|
|
328
|
+
"""
|
|
329
|
+
Add item and complete checkout
|
|
330
|
+
1. Sign in as standard_user
|
|
331
|
+
2. Add Sauce Labs Backpack to cart
|
|
332
|
+
3. Proceed through checkout
|
|
333
|
+
4. Check: Order confirmation page is shown
|
|
334
|
+
"""
|
|
335
|
+
# ...
|
|
336
|
+
|
|
337
|
+
@pytest.mark.tc(1042)
|
|
338
|
+
@pytest.mark.regression
|
|
339
|
+
def test_checkout_with_invalid_card(self):
|
|
340
|
+
"""
|
|
341
|
+
Checkout fails with invalid card
|
|
342
|
+
1. Add an item to the cart
|
|
343
|
+
2. Enter an invalid credit card number
|
|
344
|
+
3. Click Place Order
|
|
345
|
+
4. Check: Error message is displayed
|
|
346
|
+
"""
|
|
347
|
+
# ...
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Recommended config
|
|
351
|
+
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"local": {
|
|
355
|
+
"type": "python",
|
|
356
|
+
"include": ["tests/**/*.py"],
|
|
357
|
+
"exclude": ["tests/conftest.py", "tests/**/fixtures.py"]
|
|
358
|
+
},
|
|
359
|
+
"sync": {
|
|
360
|
+
"markAutomated": true
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Notes
|
|
366
|
+
|
|
367
|
+
- **`pull` is not supported** for Python files. Only `push` and `publish-test-results` apply.
|
|
368
|
+
- **Built-in pytest marks** (`parametrize`, `skip`, `skipif`, `xfail`, `usefixtures`, `filterwarnings`) are not pushed as TC tags.
|
|
369
|
+
- **`@pytest.mark.parametrize`** — parameterised data rows are not expanded into separate TCs; only the function definition is treated as the test case.
|
|
370
|
+
- **Class hierarchy** — only the immediately enclosing class is used for the `automatedTestName`. Nested classes are supported.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## JavaScript / TypeScript (Jest, Jasmine, WebdriverIO) `.js` / `.ts`
|
|
375
|
+
|
|
376
|
+
Set `local.type: "javascript"`. Supports **Jest**, **Jasmine**, and **WebdriverIO** (which uses Jest or Jasmine as its runner). All three share the same `describe()`/`it()`/`test()` API, so a single parser handles all of them.
|
|
377
|
+
|
|
378
|
+
> **Cucumber `.feature` files** are handled by `local.type: "gherkin"` — not this type.
|
|
379
|
+
|
|
380
|
+
### Detected test functions
|
|
381
|
+
|
|
382
|
+
| Function | Description |
|
|
383
|
+
|----------|-------------|
|
|
384
|
+
| `it(title, fn)` | Standard test |
|
|
385
|
+
| `test(title, fn)` | Alias for `it` |
|
|
386
|
+
| `it.only` / `test.only` | Focused test |
|
|
387
|
+
| `it.skip` / `test.skip` | Skipped test (still synced) |
|
|
388
|
+
| `xit` / `xtest` | Jasmine-style skip |
|
|
389
|
+
| `it.concurrent` / `test.concurrent` | Concurrent test |
|
|
390
|
+
|
|
391
|
+
### Source mapping
|
|
392
|
+
|
|
393
|
+
| JavaScript/TS source | Azure TC field |
|
|
394
|
+
|----------------------|---------------|
|
|
395
|
+
| JSDoc `/** ... */` first non-numbered line | TC **Title** |
|
|
396
|
+
| Numbered lines `N. text` in JSDoc | TC **Steps** (action) |
|
|
397
|
+
| Numbered lines `N. Check: text` in JSDoc | TC **Steps** (expected result, when `useExpectedResult: true`) |
|
|
398
|
+
| `// @tags: smoke, regression` above `it()` | TC **Tags** (comma-separated list) |
|
|
399
|
+
| `// @smoke` above `it()` (single-word) | TC **Tag** |
|
|
400
|
+
| `// @tc:ID` above `it()` | TC ID (written back after first push) |
|
|
401
|
+
| `{basename} > {describe} > {it title}` | `AutomatedTestName` (Jest report format) |
|
|
402
|
+
|
|
403
|
+
### Example
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
describe('Checkout', () => {
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Add item and complete checkout
|
|
410
|
+
* 1. Sign in as standard_user
|
|
411
|
+
* 2. Add Sauce Labs Backpack to cart
|
|
412
|
+
* 3. Proceed through checkout
|
|
413
|
+
* 4. Check: Order confirmation page is shown
|
|
414
|
+
*/
|
|
415
|
+
// @tc:1041 // written back by ado-sync after first push
|
|
416
|
+
// @tags: smoke, regression
|
|
417
|
+
it('adds item and completes checkout', async () => {
|
|
418
|
+
// ...
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
// @tc:1042
|
|
422
|
+
// @smoke
|
|
423
|
+
it('shows error on invalid card', async () => {
|
|
424
|
+
// ...
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
});
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Recommended config
|
|
431
|
+
|
|
432
|
+
```json
|
|
433
|
+
{
|
|
434
|
+
"local": {
|
|
435
|
+
"type": "javascript",
|
|
436
|
+
"include": ["src/**/*.spec.ts", "tests/**/*.test.js"],
|
|
437
|
+
"exclude": ["**/*.helper.ts", "**/*.fixture.ts"]
|
|
438
|
+
},
|
|
439
|
+
"sync": {
|
|
440
|
+
"markAutomated": true
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Notes
|
|
446
|
+
|
|
447
|
+
- **`pull` is not supported** for JavaScript/TypeScript files. Only `push` applies.
|
|
448
|
+
- **Dynamic titles** — `it` / `test` calls with template literals or computed values are skipped. Use string literals for reliable syncing.
|
|
449
|
+
- **`describe` nesting** — arbitrarily deep `describe()` nesting is supported. All enclosing describe titles are included in the `automatedTestName`.
|
|
450
|
+
- **Path-based auto-tagging** — directory segments starting with `@` (e.g. `tests/@smoke/`) are automatically applied as tags on all tests inside.
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## CSV `.csv`
|
|
455
|
+
|
|
456
|
+
Set `local.type: "csv"` to parse Azure DevOps / SpecSync tabular CSV exports.
|
|
457
|
+
|
|
458
|
+
**Expected column layout (9 columns):**
|
|
459
|
+
|
|
460
|
+
| Col | Field | Description |
|
|
461
|
+
|-----|-------|-------------|
|
|
462
|
+
| A (0) | ID | Azure Test Case ID — empty for new, filled after first push |
|
|
463
|
+
| B (1) | Work Item Type | Always `Test Case` (ignored) |
|
|
464
|
+
| C (2) | Title | `Scenario: My test` — non-empty on header row, empty on step rows |
|
|
465
|
+
| D (3) | Test Step | Step number — empty on header row |
|
|
466
|
+
| E (4) | Step Action | Step text, optionally prefixed with a Gherkin keyword |
|
|
467
|
+
| F (5) | Step Expected | Expected result text (optional) |
|
|
468
|
+
| G–I (6–8) | Area Path, Assigned To, State | Preserved but not used |
|
|
469
|
+
|
|
470
|
+
The first row (column headers) is always skipped automatically.
|
|
471
|
+
|
|
472
|
+
> **Note:** `ado-sync pull` is **not supported** for CSV files. Only push is supported.
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Excel `.xlsx`
|
|
477
|
+
|
|
478
|
+
Set `local.type: "excel"`. Uses the same 9-column layout as CSV. ado-sync reads the raw worksheet XML (no external xlsx library) and handles both `t="str"` and `t="inlineStr"` cells from Azure DevOps exports.
|
|
479
|
+
|
|
480
|
+
> **Note:** `ado-sync pull` is **not supported** for Excel files. Only push is supported.
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## ID tags
|
|
485
|
+
|
|
486
|
+
After a first push, ado-sync writes the Azure TC ID back into the local file.
|
|
487
|
+
|
|
488
|
+
| Format | Location |
|
|
489
|
+
|--------|----------|
|
|
490
|
+
| Gherkin | `@tc:12345` tag on its own line above the `Scenario:` line |
|
|
491
|
+
| Markdown | `@tc:12345` tag on the line immediately after the `### heading` |
|
|
492
|
+
| C# MSTest | `[TestProperty("tc", "12345")]` attribute on the test method |
|
|
493
|
+
| C# NUnit | `[Property("tc", "12345")]` attribute on the test method |
|
|
494
|
+
| Java JUnit 5 | `@Tag("tc:12345")` annotation above `@Test` |
|
|
495
|
+
| Java JUnit 4 / TestNG | `// @tc:12345` comment on the line above `@Test` |
|
|
496
|
+
| Python pytest | `@pytest.mark.tc(12345)` decorator above `def test_*` |
|
|
497
|
+
| JavaScript/TS | `// @tc:12345` comment on the line above `it()`/`test()` |
|
|
498
|
+
| CSV | Numeric ID in column A of the matching title row |
|
|
499
|
+
| Excel | Numeric ID in cell A of the matching title row |
|
|
500
|
+
|
|
501
|
+
### Custom prefix
|
|
502
|
+
|
|
503
|
+
```json
|
|
504
|
+
{ "sync": { "tagPrefix": "azure" } }
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
Result: `@azure:12345` in both Gherkin and Markdown files.
|
|
508
|
+
|
|
509
|
+
> **Warning:** Changing the prefix on an existing project means existing ID tags are no longer recognised. Do a project-wide find-and-replace before changing.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Tag filtering
|
|
514
|
+
|
|
515
|
+
All commands accept `--tags` to limit which scenarios are processed. Uses the standard Cucumber tag expression language.
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
ado-sync push --tags "@smoke"
|
|
519
|
+
ado-sync push --tags "@smoke and not @wip"
|
|
520
|
+
ado-sync pull --tags "@regression or @critical"
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
Tags are evaluated against all tags on a scenario, including:
|
|
524
|
+
|
|
525
|
+
- Tags on the `Feature` block (Gherkin)
|
|
526
|
+
- Tags on the `Scenario` / `Scenario Outline` block
|
|
527
|
+
- Tags on individual `Examples` tables
|
|
528
|
+
- Tags on the Markdown tag line (same `### heading` line or line below it)
|
|
529
|
+
- **Path-based auto-tags** — directory segments starting with `@` are automatically applied as tags:
|
|
530
|
+
|
|
531
|
+
```
|
|
532
|
+
specs/
|
|
533
|
+
@smoke/
|
|
534
|
+
login.feature ← all scenarios get tag 'smoke'
|
|
535
|
+
@regression/
|
|
536
|
+
@slow/
|
|
537
|
+
checkout.feature ← all scenarios get tags 'regression' and 'slow'
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### `local.condition` — permanent filter
|
|
541
|
+
|
|
542
|
+
Use `local.condition` in config to permanently exclude scenarios without needing `--tags` on every command:
|
|
543
|
+
|
|
544
|
+
```json
|
|
545
|
+
{ "local": { "condition": "@done and not (@ignored or @planned)" } }
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
This filter is applied before `--tags`, so it acts as a baseline inclusion gate.
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## Work item linking
|
|
553
|
+
|
|
554
|
+
Tags matching a configured `links` prefix are synced as Azure DevOps work item relations on the Test Case.
|
|
555
|
+
|
|
556
|
+
### Config
|
|
557
|
+
|
|
558
|
+
```json
|
|
559
|
+
{
|
|
560
|
+
"sync": {
|
|
561
|
+
"links": [
|
|
562
|
+
{ "prefix": "story", "relationship": "System.LinkTypes.Related" },
|
|
563
|
+
{ "prefix": "bug", "relationship": "System.LinkTypes.Related" },
|
|
564
|
+
{ "prefix": "req", "relationship": "Microsoft.VSTS.Common.TestedBy-Reverse" }
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Usage in Gherkin
|
|
571
|
+
|
|
572
|
+
```gherkin
|
|
573
|
+
@tc:1042 @story:555 @bug:789
|
|
574
|
+
Scenario: User can add items to cart
|
|
575
|
+
...
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### Usage in Markdown
|
|
579
|
+
|
|
580
|
+
```markdown
|
|
581
|
+
### User can add items to cart
|
|
582
|
+
@tc:1042 @story:555 @bug:789
|
|
583
|
+
|
|
584
|
+
Steps:
|
|
585
|
+
1. Add an item to the cart
|
|
586
|
+
...
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
On each `push`, relations are synced: new links are added, stale links (whose tag was removed) are deleted. The `relationship` value is the ADO relation type — `"System.LinkTypes.Related"` is the default if omitted.
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## Attachments
|
|
594
|
+
|
|
595
|
+
Files can be attached to Azure Test Cases via tags. See [Attachments](advanced.md#attachments).
|