@uipath/skills 1.199.0-preview.171 → 1.199.0-preview.245

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.
@@ -20,7 +20,12 @@
20
20
  # the event name, the authenticated cloud identity, the `source:
21
21
  # "skills-plugin"` dimension, and — since UiPath/cli#2806 — the
22
22
  # environment/base_url/region base dimensions stamped fresh on every event
23
- # from its own auth context (so this hook sends no environment info). This
23
+ # from its own auth context (so this hook sends no environment info). Since
24
+ # UiPath/cli#3431 the CLI also owns the session id: it resolves one per process
25
+ # (UIPATH_SESSION_ID, else an inherited agent/terminal handle) and puts it on
26
+ # App Insights' native ai.session.id tag, and `uip track` no longer accepts a
27
+ # session id from the payload — so this hook sends none. Correlation comes from
28
+ # set-session-env.ps1, which exports UIPATH_SESSION_ID for the session. This
24
29
  # hook only derives + sanitizes fields and gates on the opt-out flag; value
25
30
  # sanitization stays the hook's responsibility because the CLI and skills
26
31
  # ship co-versioned.
@@ -31,7 +36,7 @@
31
36
  # JSON-shaped text (`"success":false`, `uip solution publish`, `.flow"`,
32
37
  # `"resolvedModel":"..."`). So the payload is parsed as real JSON
33
38
  # (ConvertFrom-Json) and each field is read ONLY from the region it lives in:
34
- # ENVELOPE (top-level) -> toolName, toolUseId, session_id, permissionMode,
39
+ # ENVELOPE (top-level) -> toolName, toolUseId, permissionMode,
35
40
  # durationMs, effortLevel (effort.level), agentType,
36
41
  # source (-> session_source), reason (session-end),
37
42
  # model (-> agent_model; Claude sends it on
@@ -83,8 +88,11 @@ $ErrorActionPreference = 'SilentlyContinue'
83
88
  # eventName / session_source / reason / agent_model keys, renames
84
89
  # sessionId -> session_id (canonical casing, matches the CLI command stream,
85
90
  # UiPath/cli#2800), and drops environment/baseUrl (the CLI stamps fresh
86
- # environment/base_url/region base dimensions itself, UiPath/cli#2806).
87
- $SCHEMA_VERSION = 2
91
+ # environment/base_url/region base dimensions itself, UiPath/cli#2806). v3:
92
+ # drops session_id — the session is no longer a custom dimension; the CLI puts
93
+ # its own per-process id on the native ai.session.id tag and `uip track`
94
+ # rejects a payload session id (UiPath/cli#3431).
95
+ $SCHEMA_VERSION = 3
88
96
 
89
97
  # --- extraction helpers ------------------------------------------------------
90
98
 
@@ -270,7 +278,6 @@ function Main {
270
278
  $hookEvent = [string](Get-Prop $payload 'hook_event_name')
271
279
  $tool = [string](Get-Prop $payload 'tool_name')
272
280
  $toolUseId = [string](Get-Prop $payload 'tool_use_id')
273
- $sessionId = [string](Get-Prop $payload 'session_id')
274
281
  $permissionMode = [string](Get-Prop $payload 'permission_mode')
275
282
  $durationMs = Get-Prop $payload 'duration_ms'
276
283
  $agentType = [string](Get-Prop $payload 'agent_type')
@@ -364,7 +371,6 @@ function Main {
364
371
  @('effortLevel', 's', $effortLevel),
365
372
  @('skillsVersion', 's', $skillsVer),
366
373
  @('toolUseId', 's', $toolUseId),
367
- @('session_id', 's', $sessionId),
368
374
  @('subagentModel', 's', $subagentModel),
369
375
  @('subagentType', 's', $subagentType),
370
376
  @('agentType', 's', $agentType),
@@ -383,7 +389,8 @@ function Main {
383
389
  # the uip.skills.<event> name, stamps source: "skills-plugin", attaches the
384
390
  # authenticated cloud identity + CLI app version, owns transport + flush,
385
391
  # redacts PII, and drops any non-scalar value (so a null durationMs
386
- # disappears). Send no envelope and no `source` (the CLI overrides it).
392
+ # disappears). Send no envelope, no `source` (the CLI overrides it), and no
393
+ # session id (the CLI resolves its own and drops a payload one).
387
394
  #
388
395
  # `uip track` is never-fail (exits 0, emits nothing when telemetry is opted
389
396
  # out); piping to it is harmless even if the CLI is absent (the catch
@@ -16,7 +16,12 @@
16
16
  # the event name, the authenticated cloud identity, the `source:
17
17
  # "skills-plugin"` dimension, and — since UiPath/cli#2806 — the
18
18
  # environment/base_url/region base dimensions stamped fresh on every event
19
- # from its own auth context (so this hook sends no environment info). This
19
+ # from its own auth context (so this hook sends no environment info). Since
20
+ # UiPath/cli#3431 the CLI also owns the session id: it resolves one per process
21
+ # (UIPATH_SESSION_ID, else an inherited agent/terminal handle) and puts it on
22
+ # App Insights' native ai.session.id tag, and `uip track` no longer accepts a
23
+ # session id from the payload — so this hook sends none. Correlation comes from
24
+ # set-session-env.sh, which exports UIPATH_SESSION_ID for the session. This
20
25
  # hook only derives + sanitizes fields and gates on the opt-out flag; value
21
26
  # sanitization stays the hook's responsibility because the CLI and skills
22
27
  # ship co-versioned.
@@ -27,7 +32,7 @@
27
32
  # contains JSON-shaped text (`"success":false`, `uip solution publish`,
28
33
  # `.flow"`, `"resolvedModel":"..."`). So a single string-aware awk pass walks
29
34
  # the JSON once and pulls each field ONLY from the region it lives in:
30
- # ENVELOPE (top-level) -> toolName, toolUseId, session_id, permissionMode,
35
+ # ENVELOPE (top-level) -> toolName, toolUseId, permissionMode,
31
36
  # durationMs, effortLevel (effort.level), agentType,
32
37
  # source (-> session_source), reason (session-end),
33
38
  # model (-> agent_model; Claude sends it on
@@ -83,8 +88,11 @@ set +e
83
88
  # eventName / session_source / reason / agent_model keys, renames
84
89
  # sessionId -> session_id (canonical casing, matches the CLI command stream,
85
90
  # UiPath/cli#2800), and drops environment/baseUrl (the CLI stamps fresh
86
- # environment/base_url/region base dimensions itself, UiPath/cli#2806).
87
- SCHEMA_VERSION=2
91
+ # environment/base_url/region base dimensions itself, UiPath/cli#2806). v3:
92
+ # drops session_id — the session is no longer a custom dimension; the CLI puts
93
+ # its own per-process id on the native ai.session.id tag and `uip track`
94
+ # rejects a payload session id (UiPath/cli#3431).
95
+ SCHEMA_VERSION=3
88
96
 
89
97
  # --- extraction ------------------------------------------------------------
90
98
 
@@ -99,7 +107,7 @@ extract_fields() {
99
107
  awk '
100
108
  function interesting(k, d, c) {
101
109
  if (d == 1)
102
- return (k=="tool_name"||k=="tool_use_id"||k=="session_id"|| \
110
+ return (k=="tool_name"||k=="tool_use_id"|| \
103
111
  k=="permission_mode"||k=="duration_ms"||k=="agent_type"|| \
104
112
  k=="hook_event_name"||k=="source"||k=="reason"||k=="model")
105
113
  if (d == 2 && c == "input")
@@ -198,7 +206,7 @@ extract_fields() {
198
206
  # while loop runs in the current shell (here-doc, not a pipe), so the
199
207
  # assignments persist.
200
208
  read_fields() {
201
- event=""; tool=""; tool_use_id=""; session_id=""; permission_mode=""
209
+ event=""; tool=""; tool_use_id=""; permission_mode=""
202
210
  duration_ms=""; agent_type=""; skill=""; command=""; file_path=""
203
211
  subagent_type=""; interrupted=""; success=""; resolved_model=""
204
212
  effort_level=""; response_seen=""; session_source=""; reason=""
@@ -209,7 +217,6 @@ read_fields() {
209
217
  hook_event_name) event="$v" ;;
210
218
  tool_name) tool="$v" ;;
211
219
  tool_use_id) tool_use_id="$v" ;;
212
- session_id) session_id="$v" ;;
213
220
  permission_mode) permission_mode="$v" ;;
214
221
  duration_ms) duration_ms="$v" ;;
215
222
  agent_type) agent_type="$v" ;;
@@ -381,7 +388,6 @@ permissionMode|s|$permission_mode
381
388
  effortLevel|s|$effort_level
382
389
  skillsVersion|s|$skills_ver
383
390
  toolUseId|s|$tool_use_id
384
- session_id|s|$session_id
385
391
  subagentModel|s|$subagent_model
386
392
  subagentType|s|$subagent_type
387
393
  agentType|s|$agent_type
@@ -458,7 +464,6 @@ main() {
458
464
  effort_level="$(san "$effort_level")"
459
465
  skills_ver="$(san "$skills_ver")"
460
466
  tool_use_id="$(san "$tool_use_id")"
461
- session_id="$(san "$session_id")"
462
467
  subagent_model="$(san "$subagent_model")"
463
468
  subagent_type="$(san "$subagent_type")"
464
469
  agent_type="$(san "$agent_type")"
@@ -470,7 +475,8 @@ main() {
470
475
  # the uip.skills.<event> name, stamps source: "skills-plugin", attaches the
471
476
  # authenticated cloud identity + CLI app version, owns transport + flush,
472
477
  # redacts PII, and drops any non-scalar value (so a null durationMs
473
- # disappears). Send no envelope and no `source` (the CLI overrides it).
478
+ # disappears). Send no envelope, no `source` (the CLI overrides it), and no
479
+ # session id (the CLI resolves its own and drops a payload one).
474
480
  #
475
481
  # Detached subshell ( cmd & ) survives this hook's exit so the agent never
476
482
  # waits. `uip track` is never-fail (exits 0, emits nothing when telemetry is
@@ -6,10 +6,12 @@
6
6
  # Reads the SessionStart payload on stdin, takes its top-level `session_id`,
7
7
  # and appends `export UIPATH_SESSION_ID='<id>'` to $env:CLAUDE_ENV_FILE so
8
8
  # every subsequent shell tool subprocess — and therefore every `uip` command
9
- # the agent runs — inherits it. The CLI stamps that value as the `session_id`
10
- # dimension on native command telemetry (UiPath/cli#2800), which joins the
11
- # command stream with the skills events emitted by send-telemetry.ps1: both
12
- # streams then carry the same session id.
9
+ # the agent runs — inherits it. The CLI puts that value on App Insights'
10
+ # native `ai.session.id` tag (query it as `session_Id`) for every command it
11
+ # runs, including the `uip track` calls made by send-telemetry.ps1
12
+ # (UiPath/cli#3431) — so the command stream and the skills events share one
13
+ # session id. This export is the ONLY way they correlate: since schema v3 the
14
+ # telemetry hook sends no session id of its own.
13
15
  #
14
16
  # Registered SYNCHRONOUSLY in hooks.json (no "async": true): the write must
15
17
  # complete before the session's first shell call, or early `uip` commands
@@ -8,10 +8,12 @@
8
8
  # Reads the SessionStart payload on stdin, takes its top-level `session_id`,
9
9
  # and appends `export UIPATH_SESSION_ID='<id>'` to $CLAUDE_ENV_FILE so every
10
10
  # subsequent Bash tool subprocess — and therefore every `uip` command the
11
- # agent runs — inherits it. The CLI stamps that value as the `session_id`
12
- # dimension on native command telemetry (UiPath/cli#2800), which joins the
13
- # command stream with the skills events emitted by send-telemetry.sh: both
14
- # streams then carry the same session id.
11
+ # agent runs — inherits it. The CLI puts that value on App Insights' native
12
+ # `ai.session.id` tag (query it as `session_Id`) for every command it runs,
13
+ # including the `uip track` calls made by send-telemetry.sh (UiPath/cli#3431)
14
+ # — so the command stream and the skills events share one session id. This
15
+ # export is the ONLY way they correlate: since schema v3 the telemetry hook
16
+ # sends no session id of its own.
15
17
  #
16
18
  # Registered SYNCHRONOUSLY in hooks.json (no "async": true): the write must
17
19
  # complete before the session's first Bash call, or early `uip` commands would
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/skills",
3
- "version": "1.199.0-preview.171",
3
+ "version": "1.199.0-preview.245",
4
4
  "description": "UiPath agent skills for Claude Code, Codex, Cursor, Copilot, Gemini and OpenCode — RPA, UI automation, UI testing, coded agents/apps/workflows, and troubleshooting. Distributed as the UiPath Claude Code plugin.",
5
5
  "author": {
6
6
  "name": "UiPath"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: uipath-test
3
- description: "UiPath Test Manager — manage test projects, cases, sets, executions; generate reports. For Orchestrator→uipath-platform. For test automation→uipath-rpa."
3
+ description: "UiPath Test Manager — manage test projects, cases, sets, executions; generate reports; package and run external Playwright test suites. For Orchestrator→uipath-platform. For Studio/RPA test automation authoring→uipath-rpa."
4
4
  allowed-tools: Bash, Read, Write, Glob, Grep
5
5
  user-invocable: true
6
6
  ---
@@ -29,6 +29,7 @@ UiPath Test Manager is a web application that manages the testing lifecycle of p
29
29
  - **Test case logs** - Logs of a **test case** in an execution. A **testcase** can be navigated from **testcaselogs**.
30
30
  - **Test step logs** — Step-level logs within a **test case log**.
31
31
  - **Test case log assertions** - Assertion steps of a test case log in an execution.
32
+ - **External (Playwright) test packages** - A Playwright suite packaged as an external test package and uploaded to Orchestrator. Ingestion auto-creates one test case per Playwright test (no link step) and labels each with `PW_Tag_*`, `PW_Project_*`, `PW_Suite_*`, `PW_File_*`. These run on serverless cloud runtimes — see [references/playwright-first-mile-guide.md](references/playwright-first-mile-guide.md).
32
33
 
33
34
  CLI tool for UiPath Test Manager (`uip tm`). Use `uip tm --help` and `uip tm <command> <subcommand> --help` to discover commands and options. **Always pass `--output json`** on every `uip` command.
34
35
 
@@ -85,7 +86,7 @@ Common `uip tm` commands organized by resource type.
85
86
  | `uip tm testcases steps delete --project-key <PROJECT_KEY> --step-id <UUID> --yes` | Delete a step. |
86
87
  | `uip tm testcases list-result-history --project-key <PROJECT_KEY> --test-case-id <TEST_CASE_ID>` | List test case log result history for a specific test case. Optional `--only-failed`, `--filter`, `--limit`, `--offset`. |
87
88
  | `uip tm testcases run --project-key <PROJECT_KEY> --test-case-id <TEST_CASE_ID>` | Start a new execution for one or more test cases. **Uses `--test-case-id <UUID>` (space-separated for multiple).** Optional `--async`, `--name`, `--folder-key`, `--robot-user-key`, `--machine-key`. |
88
- | `uip tm testcases add --test-set-key <TEST_SET_KEY> --test-case-keys <KEY1,KEY2,...>` | Add test cases to a test set (comma-separated keys). |
89
+ | `uip tm testcases add --test-set-key <TEST_SET_KEY> (--test-case-keys <KEY1> <KEY2> … \| --labels <Label1> <Label2> …)` | Add test cases to a test set — by explicit keys, OR every test case carrying at least one of the given labels. Both selectors are variadic and **space-separated**: `--test-case-keys DEMO:1 DEMO:2`, `--labels PW_Tag_smoke "PW_Suite_Checkout flow"` (quote names containing spaces). Keys additionally accept the comma form (`DEMO:1,DEMO:2`); **labels do not** — `--labels A,B` is read as one label named `A,B` and matches nothing. Label matching is OR, exact and case-sensitive. The two selectors are mutually exclusive. |
89
90
  | `uip tm testcases remove --test-set-key <TEST_SET_KEY> --test-case-keys <KEY1,KEY2,...>` | Remove test cases from a test set (comma-separated keys). |
90
91
 
91
92
  > **Flag shapes for test case and step identifiers — do not interchange:**
@@ -103,10 +104,13 @@ Common `uip tm` commands organized by resource type.
103
104
  | `uip tm testsets update --test-set-key <TEST_SET_KEY> --name <TEST_SET_NAME>` | Update a test set name or description. |
104
105
  | `uip tm testsets delete --test-set-key <TEST_SET_KEY>` | Delete a test set by its key. |
105
106
  | `uip tm testsets list-testcases --project-key <PROJECT_KEY> --test-set-key <TEST_SET_KEY>` | List test cases assigned to a test set. |
106
- | `uip tm testsets run --test-set-key <TEST_SET_KEY>` | Run a test set and return the execution ID. Optional `--execution-type <automated\|manual\|mixed\|none>` (default `automated`), `--input-path <FILE>` for parameter overrides. |
107
+ | `uip tm testsets run --test-set-key <TEST_SET_KEY>` | Run a test set and return the execution ID. Optional `--execution-type <automated\|manual\|mixed\|none>` (default `automated`), `--input-path <FILE>` for parameter overrides. For Playwright test sets, optional `--playwright-projects <names...>` — see the note below. |
108
+ | `uip tm testsets playwright-context --test-set-key <TEST_SET_KEY>` | Probe whether a test set is a Playwright test set: returns `IsPlaywright` plus the available and selected Playwright project names. |
107
109
 
108
110
  > Keys use the format `PROJECT_KEY:NUMBER` (e.g., `INV:42`). To add or remove test cases in a test set, use `uip tm testcases add` / `uip tm testcases remove` — those verbs live under the `testcases` group, not under `testsets`.
109
111
 
112
+ > **Playwright test sets:** `--playwright-projects <names...>` (space-separated, case-sensitive `playwright.config` project names) runs only the selected projects and persists the selection on the test set. It requires every test case in the set to come from one Playwright package; unknown names fail fast listing the valid ones. Probe first with `playwright-context` and branch on `IsPlaywright`. Both need a Test Manager with Playwright support and a CLI carrying the external-package commands — [references/playwright-first-mile-guide.md](references/playwright-first-mile-guide.md) opens with the check to run and what to do when they are absent.
113
+
110
114
  ### Executions Commands
111
115
 
112
116
  | Command | Purpose |
@@ -141,7 +145,7 @@ Common `uip tm` commands organized by resource type.
141
145
 
142
146
  | Command | Purpose |
143
147
  |---|---|
144
- | `uip tm report get --execution-id <EXECUTION_ID>` | Get a summary report for a completed test execution. Optional `--project-key`, `--test-set-key`, `--query`. |
148
+ | `uip tm report get --execution-id <EXECUTION_ID> (--project-key <KEY> \| --test-set-key <KEY>)` | Get a summary report for a completed test execution. One of `--project-key`/`--test-set-key` is required to identify the project (verified: passing only `--execution-id` exits with "Provide --project-key or --test-set-key"). |
145
149
 
146
150
  ### Attachment Commands
147
151
 
@@ -156,6 +160,14 @@ Common `uip tm` commands organized by resource type.
156
160
  |---|---|
157
161
  | `uip tm result download --execution-id <EXECUTION_ID>` | Download test execution results as JUnit XML. Optional `--project-key`, `--test-set-key`, `--result-path <DIR>`. |
158
162
 
163
+ ### Pack Commands (Playwright)
164
+
165
+ | Command | Purpose |
166
+ |---|---|
167
+ | `uip tm pack --project-path <dir> --type playwright --project-key <PROJECT_KEY> --name <PackageName> --package-version <ver> -o <out-dir>` | Pack a Playwright suite into a `.nupkg` external test package. Requires a lockfile and `@playwright/test` in the project. `--package-version` takes a NuGet/SemVer-style version — three numeric parts, optional prerelease suffix (`1.0.0`, `1.0.1-beta.1`); `1.0` or a non-numeric string is rejected. `--project-key` targets the Test Manager project where ingestion auto-creates the test cases; `--no-create-test-cases` skips that; `--dry-run` previews. Upload with `uip or packages upload <nupkg>`. |
168
+
169
+ > Packing is offline — no auth needed. The upload → ingestion → label-fill → run pipeline is in [references/playwright-first-mile-guide.md](references/playwright-first-mile-guide.md).
170
+
159
171
  ### Wait Commands
160
172
 
161
173
  | Command | Purpose |
@@ -223,7 +235,7 @@ Object labels are tag-style metadata applied to Requirement, TestCase, TestSet,
223
235
  4. **Cap retries at 3** for any failing `uip` CLI command. After 3 failures, stop and report the error to the user (see Rule — never fall back to direct REST APIs).
224
236
  5. **Handle empty results** — if a list command returns an empty array, stop and inform the user rather than proceeding with a null key.
225
237
  6. **Confirm before delete** — always confirm the target resource key with the user before running any `delete` command. All delete commands require `--yes` (or `-y`) to proceed; omitting it exits without deleting.
226
- 7. **For operations requiring folder key** — use `uip or folders list -n <folder-name> --all --output json` (run `/uipath-platform` for folder management details).
238
+ 7. **For operations requiring folder key** — use `uip or folders list -n <folder-name> --all --output json` when the user named a folder; when picking one yourself, list without `--all` so you only get folders you are a member of (run `/uipath-platform` for folder management details).
227
239
  8. **Discover before assuming** — never guess automation names, folder keys, project IDs, or test case keys. Always run the matching `list` command first (e.g., `uip tm testcases list-automations`, `uip or folders list -n <folder-name> --all`).
228
240
  9. **Narrow `list` calls server-side when the user names an entity.** When the user provides a name, key, label, or tag, check `uip tm <resource> list --help` (or `uip or <resource> list --help`) for the narrowing flag the command exposes and pass it on the `list` call. Never list all results and filter client-side — it wastes tokens and misses paginated entries. Applies to every entity across `uip tm` and `uip or`.
229
241
  10. **Set default folder before any `run` command** — `uip tm testcases run` and `uip tm testsets run` both require a default Orchestrator folder on the project. Run `uip tm project set-default-folder --project-key <PROJECT_KEY> --folder-key <FOLDER_KEY> --output json` first. Get folder keys with `uip or folders list -n <folder-name> --all --output json`.
@@ -305,7 +317,8 @@ If the probe in Rule #2 shows singular subjects, the CLI predates the closed-ver
305
317
  | I want to... | Start here |
306
318
  |---|---|
307
319
  | **Generate a shareable test report** (tester or release manager view) | [references/test-result-report-guide.md](references/test-result-report-guide.md) |
308
- | **Publish a project and link it to a Test Manager test case** | [references/publish-and-link-guide.md](references/publish-and-link-guide.md) |
320
+ | **Publish a project and link it to a Test Manager test case** (Studio/RPA) | [references/publish-and-link-guide.md](references/publish-and-link-guide.md) |
321
+ | **Pack, ingest, and run a Playwright suite on serverless** (pack → upload → labels → run) | [references/playwright-first-mile-guide.md](references/playwright-first-mile-guide.md) |
309
322
 
310
323
 
311
324
  ## Anti-patterns
@@ -313,3 +326,4 @@ If the probe in Rule #2 shows singular subjects, the CLI predates the closed-ver
313
326
  - **Do NOT proceed if authentication fails** — all Test Manager API calls require a valid bearer token. Fail fast rather than surfacing confusing 401 errors later.
314
327
  - **Do NOT skip the surface probe** (Critical Rule #2). On a pre-rename CLI, post-rename commands fail with `unknown command`; on a post-rename CLI, pre-rename commands fail the same way. The skill targets the post-rename surface and falls back per the [Pre-rename fallbacks](#pre-rename-fallbacks) table. Picking the wrong shape without probing burns a retry on every call.
315
328
  - **Do NOT guess command names — verb-noun composites are required.** The CLI uses explicit verb-noun forms; bare verbs do not exist. Confirm with `uip tm <resource> --help --output json`.
329
+ - **Do NOT `link-automation` Playwright test cases.** Playwright ingestion links them to the package automatically; the manual link step belongs to the Studio/RPA pipeline only.
@@ -0,0 +1,208 @@
1
+ # Playwright First Mile — Pack, Ingest, and Run on Serverless
2
+
3
+ End-to-end pipeline: take a Playwright test suite from a repo to executed results in UiPath Test Manager, using only `uip` commands. This flow is **Playwright-specific** — the pack command, the auto-created test cases, the `PW_*` labels, and the per-project run selection below do NOT apply to UiPath Studio/RPA packages. For Studio test automation use [publish-and-link-guide.md](publish-and-link-guide.md) instead; never mix the two pipelines.
4
+
5
+ ## Pipeline
6
+
7
+ ```
8
+ uip tm pack --type playwright → .nupkg with embedded test metadata
9
+ uip or packages upload → package on the Orchestrator feed
10
+ (Test Manager ingestion, automatic) → test cases auto-create, PW_* labels applied
11
+ uip tm testsets create → empty test set
12
+ uip tm testcases add --labels → fill it by label
13
+ uip tm testsets playwright-context → probe: is this a Playwright test set? which projects?
14
+ uip tm testsets run [--playwright-projects <names...>] → execute on serverless
15
+ uip tm wait / report / result → outcome
16
+ ```
17
+
18
+ The key difference from the RPA pipeline: there is **no link step**. Uploading the package is enough — ingestion creates one Test Manager test case per discovered Playwright test, already bound to the package, and labels each with:
19
+
20
+ - `PW_Tag_<tag>` — one per Playwright tag (`@smoke` → `PW_Tag_smoke`)
21
+ - `PW_Project_<name>` — one per Playwright project the test runs in
22
+ - `PW_Suite_<name>` / `PW_Path_<chain>` — describe-block grouping (name and full chain)
23
+ - `PW_File_<path>` — the spec file
24
+
25
+ > **Do NOT run `uip tm testcases link-automation` on Playwright test cases.** They are linked by ingestion; manual linking is the RPA pipeline and will corrupt the association.
26
+
27
+ > **Reading command output.** `--output json` prints a JSON envelope, but not on its own line: auto-updater chatter (including `Update completed with failures.`, which is unrelated to your command), `Resolved project …` progress lines and trailing telemetry warnings share the same stream. Judge a command by the `Result` field inside the envelope, never by surrounding text, and extract from the first `{` before parsing.
28
+
29
+ > **If a command is missing.** Two commands in this pipeline are hidden from `--help`, so `--help` is not a reliable way to tell whether a build has them: `testsets playwright-context` (Step 5) and `run --playwright-projects` (Step 6). Older CLIs answer `unknown command` / `unknown option` for them. Treat them differently:
30
+ >
31
+ > - **Probe missing** → skip Step 5 and continue. The probe only *reports* whether a test set is Playwright; it does not enable anything, so losing it costs you the pre-check, not the capability. Project scoping still works.
32
+ > - **`--playwright-projects` rejected** → this build cannot scope a run to selected projects. Run the test set without the flag (every project in the package's config runs) rather than retrying.
33
+
34
+ ## Prerequisites
35
+
36
+ - A Test Manager project to land the test cases in: `uip tm project list --filter <name> --output json`, or `uip tm project create --name <NAME> --project-key <PROJECT_KEY> --output json`. Capture the project key.
37
+ - The tenant's Test Manager must have Playwright support enabled (a server-side feature flag). If ingestion never produces test cases (Step 3), this is the first thing to suspect — stop and ask the user.
38
+ - The Playwright project directory must contain:
39
+ - `package.json` with `@playwright/test` installed (discovery shells out to the project's own `playwright test --list`; no browsers needed),
40
+ - a **lockfile** (`package-lock.json` / `yarn.lock` / `pnpm-lock.yaml` / `bun.lock`) — serverless does a deterministic install,
41
+ - a `playwright.config` file.
42
+
43
+ ## Step 1 — Pack
44
+
45
+ ```bash
46
+ uip tm pack --project-path <dir> --type playwright \
47
+ --project-key <PROJECT_KEY> --name <PackageName> \
48
+ --package-version 1.0.0 -o <out-dir> --output json
49
+ ```
50
+
51
+ - `--project-key` is **required** by default because test-case auto-creation is on; pass `--no-create-test-cases` to pack without it (label metadata stays embedded for later use).
52
+ - Preview with `--dry-run` (writes nothing).
53
+ - Capture `Data.Output` (the `.nupkg` path) and `Data.TestCount` from the JSON output. `TestCount` is the number of test cases ingestion will create — remember it for Step 3.
54
+ - Pack fails loudly when the lockfile or `@playwright/test` is missing — fix the project, do not improvise around it.
55
+
56
+ ## Step 2 — Upload to Orchestrator
57
+
58
+ ```bash
59
+ uip or packages upload "<out-dir>/<PackageName>.1.0.0.nupkg" --output json
60
+ ```
61
+
62
+ `--package-version` is a NuGet/SemVer-style version: three numeric parts with an optional prerelease suffix (`1.0.0`, `1.0.1-beta.1`) — `1.0` is rejected. Each upload needs a version the feed does not already have, so before re-packing check what is published and go above it:
63
+
64
+ ```bash
65
+ uip or packages list --search <PackageName> --output json
66
+ ```
67
+
68
+ The match returns the feed's **latest** version only (one row, `IsLatestVersion: true`) — enough to pick the next version, but it is not a version history.
69
+
70
+ ## Step 3 — Wait for ingestion
71
+
72
+ Ingestion is asynchronous and automatic. Poll until the auto-created test cases appear:
73
+
74
+ ```bash
75
+ uip tm testcases list --project-key <PROJECT_KEY> --output json
76
+ ```
77
+
78
+ - Poll **unfiltered**. Do NOT pass `--filter <PackageName>` — `--filter` matches a test case's name or key by **prefix**, and an ingested test case is named `"<suite> > <test title>"`, so a package name never matches: the call stays empty forever and reads as a false "ingestion never happened".
79
+ - The rows carry `TestCaseKey` (e.g. `SHIP:1`) plus `Id` (the UUID) and `Name` — count `TestCaseKey`, not `Id`, when polling.
80
+ - Ingestion is done when `TestCount` new test cases from Step 1 are present, each named `"<suite> > <test title>"`. A plain `pack` prints only `Package`, `Output` and `TestCount` — if you want the exact expected names up front, run `--dry-run` first or read `testCases.json` inside the `.nupkg`; otherwise match on the count plus that name shape.
81
+ - `TestCount` from Step 1 is one test case per Playwright **test** — it is not multiplied by the number of Playwright projects (2 tests × 2 projects → 2 test cases).
82
+ - Ingested test cases show `IsAutomated: false` in list output; that is normal and does not mean ingestion failed.
83
+ - Poll every ~10 seconds for up to ~3 minutes. If the expected names never appear, STOP and report — the likely causes are the Playwright feature flag being off for the tenant or a wrong `--project-key`, and neither is fixed by retrying.
84
+ - Spot-check the labels landed: `uip tm objectlabel list --project-key <PROJECT_KEY> --object-type TestCase --filter PW_ --output json` (returns distinct label *names* only).
85
+
86
+ ## Step 4 — Set the default folder, create a test set, fill it by label
87
+
88
+ Set the project's default Orchestrator folder FIRST — both the Step 5 probe and the Step 6 run resolve packages through it (Critical Rule #10):
89
+
90
+ ```bash
91
+ uip or folders list --output json # WITHOUT --all: only folders you are a member of
92
+ uip tm project set-default-folder --project-key <PROJECT_KEY> --folder-key <FOLDER_KEY> --output json
93
+ ```
94
+
95
+ - Pick the folder from the **unflagged** `folders list` — `--all` returns every folder *visible* to you, including ones where you have no rights; choosing one of those fails later with `folderNotFoundOrNoAccess`.
96
+ The folder needs **two** things, and missing either one fails the run differently:
97
+
98
+ - **A Cloud Robots – Serverless machine** — without it job creation 500s and the execution is instantly `Cancelled`. Check with `uip or machines list --folder-key <FOLDER_KEY> --output json`; if none, create and assign one (one serverless machine per folder):
99
+
100
+ ```bash
101
+ uip or machines create -n <name> --serverless --testing-slots 2 --output json # capture Data.Key
102
+ uip or machines assign <MACHINE_KEY> --folder-key <FOLDER_KEY> --output json # takes machine KEYS (GUIDs), not names
103
+ ```
104
+
105
+ - **A folder member who can run unattended** — the run executes as a robot user drawn from the folder, and `uip tm testsets run` has no flag to choose one (only `uip tm testcases run` does), so folder membership is the only lever:
106
+
107
+ ```bash
108
+ uip or users list-in-folder --folder-key <FOLDER_KEY> --output json
109
+ uip or users get <USER_KEY> --all-fields --output json # needs MayHaveUnattendedSession: true
110
+ ```
111
+
112
+ Folder, machine and robot-user management is the platform skill's domain — see [/uipath:uipath-platform § orchestrator/setup-environment.md](../../uipath-platform/references/orchestrator/setup-environment.md) for the authoritative flags and the one-serverless-machine-per-folder rule. An ordinary interactive user usually has `MayHaveUnattendedSession: false`, and `uip or users update --allow-unattended` cannot fix that here — it requires a Windows unattended username and password, which serverless does not use. Assign an already-unattended-capable principal instead (a `DirectoryRobot` account is the reliable pick). Creating your own folder is a first-class option when no existing one qualifies: `uip or folders create <NAME> --output json` (name is positional), then attach a machine and such a user.
113
+
114
+ ```bash
115
+ uip tm testsets create --project-key <PROJECT_KEY> --name "PW Smoke" --output json
116
+ uip tm testcases add --test-set-key <TEST_SET_KEY> --labels "PW_File_<path>" --output json
117
+ ```
118
+
119
+ - Capture `TestSetKey` from the create output (e.g. `DEMO:10`).
120
+ - `--labels` is variadic and space-separated (quote names that contain spaces). Matching is **OR across labels, exact, and case-sensitive** — discover the real names first with `uip tm objectlabel list` rather than guessing.
121
+ - `--labels` works with any object label; the `PW_*` labels are simply what ingestion applies.
122
+ - Mutually exclusive with `--test-case-keys`; pass exactly one of the two.
123
+ - To run the whole suite on one browser: fill by a suite/file label (`PW_Suite_*` or `PW_File_*`) and pass the browser to `--playwright-projects` in Step 6. Filling by `PW_Project_<name>` is for selecting the subset of tests that participate in that project — it does not restrict which browsers run.
124
+ - **Labels select *tests*; `--playwright-projects` selects *browsers*.** Filling by `PW_Project_firefox` picks every test that runs in the firefox project (often all of them); it does not make the run firefox-only — that is what the run flag in Step 6 does. To "run only <project>", label-fill by whatever identifies the tests you want (tag, suite, file) and pass the project name to `--playwright-projects`.
125
+ - **Keep one test set = one Playwright package.** Per-project selection (Step 6) requires every test case in the set to come from a single Playwright package; label-filling across packages produces a set that cannot be project-scoped. Labels are NOT package-qualified — in a project holding several Playwright packages, a generic label like `PW_Tag_smoke` matches tests from all of them. There, fill by a package-unique label (`PW_File_<path>`, or a suite name unique to the package) or by explicit `--test-case-keys` from the current ingestion.
126
+
127
+ ## Step 5 — Probe the Playwright context (when available)
128
+
129
+ Before deciding whether `--playwright-projects` applies, ask the server:
130
+
131
+ ```bash
132
+ uip tm testsets playwright-context --test-set-key <TEST_SET_KEY> --output json
133
+ ```
134
+
135
+ Read the fields off the JSON response rather than relying on the names below staying current — this list describes today's shape, and `--output json` always carries whatever the API returns.
136
+
137
+ - `Data.IsPlaywright: true` → the set resolves to one Playwright package; `AvailablePlaywrightProjects` holds the only valid `--playwright-projects` values, and `SelectedPlaywrightProjects` shows any selection already stored on the test set. Both are **comma-joined strings** (`"chromium, firefox"`), not arrays — split on `", "` when scripting; no stored selection is `""`.
138
+ - `Data.IsPlaywright: false` → RPA, mixed, manual, or multi-package test set — run it **without** `--playwright-projects`.
139
+ - The server never errors on type here, so this is the safe discriminator for automation: probe first, branch on `IsPlaywright`.
140
+ - **False negative without a folder:** the probe resolves the package through the project's default folder — if that isn't set (Step 4), a genuine Playwright test set reports `IsPlaywright: false`. Set the default folder before trusting a `false`.
141
+
142
+ ## Step 6 — Run, optionally per Playwright project
143
+
144
+ ```bash
145
+ uip tm testsets run --test-set-key <TEST_SET_KEY> \
146
+ --playwright-projects chromium --output json
147
+ ```
148
+
149
+ `--playwright-projects` does not appear in `uip tm testsets run --help` — functional but unlisted, so treat this guide as its reference rather than concluding the build lacks it. Semantics (all enforced with clear errors, nothing silently ignored):
150
+
151
+ - Space-separated, case-sensitive names from the package's `playwright.config`. Passing several (`chromium firefox`) runs all of them, but results stay one log per test case — not per browser — so a per-browser breakdown is not available from Test Manager; scope to one project when you need attributable results. Unknown names **fail fast, before anything is persisted**, listing the available projects.
152
+ - Valid only when every test case in the set comes from one single Playwright package (see Step 4); fails for Studio/RPA test sets — run those without the flag.
153
+ - The selection **persists on the test set** and applies to later runs until changed; omit the flag to reuse the stored selection (or the config's defaults if none was ever stored).
154
+ - On a Test Manager without Playwright support the command fails with instructions rather than running incorrectly.
155
+
156
+ Omit `--playwright-projects` entirely for a plain run (all config-default projects).
157
+
158
+ **Getting the execution id.** Start the run **without** `--wait`: it returns a complete JSON envelope immediately, carrying `ExecutionId` and `Status: Pending` — the cleanest handle for automation. With `--wait` the envelope only arrives at terminal state, so take the id from the `Execution started: <id> (Pending)` progress line — not from `Starting execution for test set …`, whose UUID is the *test set*.
159
+
160
+ **Agent-friendly waiting:** a single `--wait` call can sit silent for many minutes, which trips agent-harness watchdogs and shell timeouts. When running as an agent, prefer starting the run **without** `--wait`, then poll in bounded chunks: `uip tm wait --execution-id <EXECUTION_ID> --timeout 120 --output json` in a loop (or `uip tm executions get-stats` every 30–60 s), so every call returns quickly and progress stays visible. `wait` polls on a fixed 60 s interval, so keep `--timeout` a multiple of that — a shorter timeout can report a timeout for a run that already finished. A `wait` that hits its `--timeout` returns a Failure envelope with `Retry: "RetryWillNotFix"` — for a non-terminal execution that just means "still running"; keep polling, don't treat it as fatal.
161
+
162
+ ## Step 7 — Results
163
+
164
+ - `--wait` on the run blocks until terminal; without it, use `uip tm wait --execution-id <EXECUTION_ID> --output json`.
165
+ - Summary: `uip tm report get --execution-id <EXECUTION_ID> --project-key <PROJECT_KEY> --output json` (`--project-key` or `--test-set-key` is required — bare `--execution-id` exits with "Provide --project-key or --test-set-key").
166
+ - Per-test detail: `uip tm executions testcaselogs list --execution-id <EXECUTION_ID> --project-key <PROJECT_KEY> --output json`. Judge pass/fail by `Result` (`Passed` / `Failed` / `None`) — a failed test still reports `HasError: false`, so that field is not the outcome.
167
+ - JUnit export: `uip tm result download --execution-id <EXECUTION_ID> --result-path <dir> --output json` — counts only for Playwright: the XML names every case after the spec file, not the test title, so use `testcaselogs list` when you need to know *which* test failed.
168
+ - **Proving the run was scoped as asked:** `uip tm executions get-stats --execution-id <EXECUTION_ID> --project-key <PROJECT_KEY> --output json` returns a `PlaywrightExecutionSnapshot` whose `Projects` is the project list the run actually used (`["chromium"]`). Read only `Projects` from it — its `Version` is two-component (`1.0`), like `list-automations` and `playwright-context`, so none of the three can tell 1.0.1 from 1.0.0; `TestCaseVersion` on the logs is the only field that can. Counting logs proves nothing here — there is one test case log per Playwright **test**, not per test × project, so a two-project run yields the same number of logs as a one-project run.
169
+
170
+ Execution happens on UiPath serverless cloud runtimes — no robot or package deployment into the folder is needed beyond the upload in Step 2, but the folder does need its serverless machine assignment (Step 4).
171
+
172
+ ### When a run produces no results
173
+
174
+ Three shapes, one rule: diagnose with the two commands below, then stop — retrying doesn't fix any of them.
175
+
176
+ - **`Cancelled` within seconds**, logs pointing at `CreateTestAutomationJobs` / `InternalServerError` → the default folder has no serverless machine assigned (Step 4).
177
+ - **`Finished` with `Passed: 0 / Failed: 0 / None: N`** → the run ended without per-test results reaching Test Manager; the test case log's `Info` carries the reason (results upload failed, or the job never started). Note `report get` counts `None` as **`Skipped`**, so 0% here means "results lost", not "tests skipped".
178
+ - **Stuck `Pending`** → dispatch worked but nothing is executing. A faulted job may never sync back, so don't sit out the 30-minute wait; check after ~5 minutes. Fixing the folder does **not** rescue an already-pending execution — start a new run after fixing.
179
+ - **`Serverless.Runtime.CannotIssueUserTokenDueToUserNotPartOfOrg`** in a log's `Info` → the folder's robot-user pool is bad: the account Test Manager picked is still folder-assigned but no longer valid in the org. Unlike the shapes above this **is** fixable from the CLI — point the project at a folder whose members satisfy Step 4 (or create one), then re-run.
180
+
181
+ ```bash
182
+ uip tm executions testcaselogs list --execution-id <EXECUTION_ID> --project-key <PROJECT_KEY> --output json
183
+ uip or jobs list --folder-key <FOLDER_KEY> --output json
184
+ ```
185
+
186
+ Everything past the Test Manager boundary — job states, machines, folder membership — belongs to [/uipath:uipath-platform § orchestrator/run-jobs.md](../../uipath-platform/references/orchestrator/run-jobs.md) and [§ orchestrator/setup-environment.md](../../uipath-platform/references/orchestrator/setup-environment.md); use those for the job-side detail. A `Duration` of `00:00:00` and an empty `StartTime` on an already-finished execution are normal — not evidence of a broken run. `JobKey` values on the logs prove Test Manager dispatched; jobs `Faulted` with no host machine mean the tenant can't run them. Either way it needs the platform team — report it rather than re-running (there is no CLI verb to cancel a Test Manager execution).
187
+
188
+ ## Iterating on the suite (and getting a fix back in)
189
+
190
+ Changing a test — including fixing one the run just failed — uses the same pipeline with a bumped version:
191
+
192
+ ```bash
193
+ uip tm pack --project-path <dir> --type playwright --project-key <PROJECT_KEY> --name <PackageName> --package-version 1.0.1 -o <out-dir> --output json
194
+ uip or packages upload "<out-dir>/<PackageName>.1.0.1.nupkg" --output json
195
+ ```
196
+
197
+ The version **must** be new — the Orchestrator feed rejects one it already has (Step 2). Ingestion then **updates** the existing test cases in place (matched per test), creates any new ones, and unlinks removed ones, so:
198
+
199
+ - **A test set keeps its membership** when the test list is unchanged — nothing to re-add, no new test set, re-run the same `--test-set-key`. Only re-run `uip tm testcases add --labels` if new tests should join.
200
+ - **A stored Playwright project selection survives** too, so the re-run stays scoped.
201
+
202
+ **Confirming the new package actually ran:** the test case logs carry `TestCaseVersion`, so after the re-run
203
+
204
+ ```bash
205
+ uip tm executions testcaselogs list --execution-id <EXECUTION_ID> --project-key <PROJECT_KEY> --output json
206
+ ```
207
+
208
+ reports the version you just packed (`1.0.1`). That is the reliable check — `list-automations` shows a two-component `PackageVersion` (`1.0`) that cannot distinguish 1.0.1 from 1.0.0. Ingestion of an update is otherwise invisible (same count, same names), so allow ~60–90 s after the upload before re-running; an old `TestCaseVersion` in the results means a stale package, not a bad fix.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "skillsVersion": "1.199.0-preview.171",
3
+ "skillsVersion": "1.199.0-preview.245",
4
4
  "targetCli": "^1.199.0"
5
5
  }