doc-detective 3.0.17 → 3.1.0-dev.2

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.
@@ -0,0 +1,174 @@
1
+ name: Auto Dev Release
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ # Don't trigger on release events to avoid conflicts with main release workflow
8
+ workflow_dispatch:
9
+ # Allow manual triggering for testing
10
+
11
+ jobs:
12
+ auto-dev-release:
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 10
15
+ # Skip if this is a release commit or docs-only changes
16
+ if: |
17
+ !contains(github.event.head_commit.message, '[skip ci]') &&
18
+ !contains(github.event.head_commit.message, 'Release') &&
19
+ github.event_name != 'release'
20
+
21
+ steps:
22
+ - name: Checkout code
23
+ uses: actions/checkout@v4
24
+ with:
25
+ # Need full history for proper version bumping
26
+ fetch-depth: 0
27
+ # Use a token that can push back to the repo
28
+ token: ${{ secrets.DD_DEP_UPDATE_TOKEN }}
29
+
30
+ - name: Setup Node.js
31
+ uses: actions/setup-node@v4
32
+ with:
33
+ node-version: '18'
34
+ cache: 'npm'
35
+ cache-dependency-path: package-lock.json
36
+ registry-url: 'https://registry.npmjs.org/'
37
+
38
+ - name: Check for documentation-only changes
39
+ id: check_changes
40
+ run: |
41
+ # Always release on workflow_dispatch
42
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
43
+ echo "skip_release=false" >> $GITHUB_OUTPUT
44
+ echo "Manual trigger: proceeding with release"
45
+ exit 0
46
+ fi
47
+
48
+ # Get list of changed files
49
+ CHANGED_FILES=$(git diff --name-only ${{ github.event.before }}..${{ github.event.after }})
50
+
51
+ echo "Changed files:"
52
+ echo "$CHANGED_FILES"
53
+
54
+ # Check if only documentation files changed
55
+ if echo "$CHANGED_FILES" | grep -v -E '\.(md|txt|yml|yaml)$|^\.github/' | grep -q .; then
56
+ echo "skip_release=false" >> $GITHUB_OUTPUT
57
+ echo "Code changes detected, proceeding with release"
58
+ else
59
+ echo "skip_release=true" >> $GITHUB_OUTPUT
60
+ echo "Only documentation changes detected, skipping release"
61
+ fi
62
+
63
+ - name: Validate package.json
64
+ if: steps.check_changes.outputs.skip_release == 'false'
65
+ run: |
66
+ # Validate package.json exists and is valid JSON
67
+ if [ ! -f "package.json" ]; then
68
+ echo "❌ package.json not found"
69
+ exit 1
70
+ fi
71
+
72
+ # Validate JSON syntax
73
+ if ! node -p "JSON.parse(require('fs').readFileSync('package.json', 'utf8'))" > /dev/null 2>&1; then
74
+ echo "❌ package.json is not valid JSON"
75
+ exit 1
76
+ fi
77
+
78
+ # Check for required fields
79
+ if ! node -p "require('./package.json').name" > /dev/null 2>&1; then
80
+ echo "❌ package.json missing 'name' field"
81
+ exit 1
82
+ fi
83
+
84
+ if ! node -p "require('./package.json').version" > /dev/null 2>&1; then
85
+ echo "❌ package.json missing 'version' field"
86
+ exit 1
87
+ fi
88
+
89
+ echo "✅ package.json validation passed"
90
+
91
+ - name: Install dependencies
92
+ if: steps.check_changes.outputs.skip_release == 'false'
93
+ run: npm ci
94
+
95
+ - name: Run tests
96
+ if: steps.check_changes.outputs.skip_release == 'false'
97
+ run: npm test
98
+
99
+ - name: Configure Git
100
+ run: |
101
+ git config --global user.name 'github-actions[bot]'
102
+ git config --global user.email 'github-actions[bot]@users.noreply.github.com'
103
+
104
+ - name: Generate dev version
105
+ if: steps.check_changes.outputs.skip_release == 'false'
106
+ id: version
107
+ run: |
108
+ # Get current version from package.json
109
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
110
+ echo "Current version: $CURRENT_VERSION"
111
+
112
+ # Extract base version (remove existing -dev.X suffix if present)
113
+ BASE_VERSION=$(echo $CURRENT_VERSION | sed 's/-dev\.[0-9]*$//')
114
+ echo "Base version: $BASE_VERSION"
115
+
116
+ # Check if we need to get the latest dev version from npm
117
+ LATEST_DEV=$(npm view doc-detective@dev version 2>/dev/null || echo "")
118
+
119
+ if [ -n "$LATEST_DEV" ] && [[ $LATEST_DEV == $BASE_VERSION-dev.* ]]; then
120
+ # Extract the dev number and increment it
121
+ DEV_NUM=$(echo $LATEST_DEV | grep -o 'dev\.[0-9]*$' | grep -o '[0-9]*$')
122
+ NEW_DEV_NUM=$((DEV_NUM + 1))
123
+ else
124
+ # Start with dev.1
125
+ NEW_DEV_NUM=1
126
+ fi
127
+
128
+ NEW_VERSION="$BASE_VERSION-dev.$NEW_DEV_NUM"
129
+ echo "New version: $NEW_VERSION"
130
+
131
+ # Update package.json
132
+ npm version $NEW_VERSION --no-git-tag-version
133
+
134
+ # Set outputs
135
+ echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
136
+ echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT
137
+
138
+ - name: Commit version change
139
+ if: steps.check_changes.outputs.skip_release == 'false'
140
+ run: |
141
+ git add package.json package-lock.json
142
+ git commit -m "Auto dev release: v${{ steps.version.outputs.version }} [skip ci]"
143
+
144
+ - name: Create and push git tag
145
+ if: steps.check_changes.outputs.skip_release == 'false'
146
+ run: |
147
+ git tag "v${{ steps.version.outputs.version }}"
148
+ git push origin "v${{ steps.version.outputs.version }}"
149
+ git push origin main
150
+
151
+ - name: Publish to npm
152
+ if: steps.check_changes.outputs.skip_release == 'false'
153
+ run: |
154
+ # Add error handling for npm publish
155
+ set -e
156
+ echo "📦 Publishing to npm with 'dev' tag..."
157
+ npm publish --tag dev
158
+ echo "✅ Successfully published to npm"
159
+ env:
160
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
161
+
162
+ - name: Summary
163
+ if: steps.check_changes.outputs.skip_release == 'false'
164
+ run: |
165
+ echo "✅ Auto dev release completed successfully!"
166
+ echo "📦 Version: v${{ steps.version.outputs.version }}"
167
+ echo "🏷️ NPM Tag: dev"
168
+ echo "📋 Install with: npm install doc-detective@dev"
169
+
170
+ - name: Skip summary
171
+ if: steps.check_changes.outputs.skip_release == 'true'
172
+ run: |
173
+ echo "⏭️ Auto dev release skipped"
174
+ echo "📝 Only documentation changes detected"
@@ -46,6 +46,7 @@ jobs:
46
46
  echo "Failed to install doc-detective-core@${{ steps.version.outputs.version }} or doc-detective-common@${{ steps.common_version.outputs.common_version }}"
47
47
  exit 1
48
48
  }
49
+ npm audit fix
49
50
 
50
51
  - name: Test the installation
51
52
  run: |
@@ -64,24 +65,88 @@ jobs:
64
65
  echo "has_changes=true" >> $GITHUB_OUTPUT
65
66
  fi
66
67
 
67
- - name: Bump patch version
68
+ - name: Bump or sync version
68
69
  id: patch
69
70
  if: steps.commit.outputs.has_changes == 'true'
70
71
  run: |
71
72
  git checkout -- .
72
73
  git clean -fd
73
- npm version patch
74
+ # Get current project version
75
+ PROJ_VERSION=$(node -p "require('./package.json').version")
76
+ # Get doc-detective-core version (strip ^ or ~)
77
+ CORE_VERSION=$(node -p "(require('./package.json').dependencies['doc-detective-core'] || require('./package.json').devDependencies['doc-detective-core'] || '').replace(/^[^\\d]*/, '')")
78
+ # Parse versions
79
+ PROJ_MAJOR=$(echo $PROJ_VERSION | cut -d. -f1)
80
+ PROJ_MINOR=$(echo $PROJ_VERSION | cut -d. -f2)
81
+ core_MAJOR=$(echo $CORE_VERSION | cut -d. -f1)
82
+ core_MINOR=$(echo $CORE_VERSION | cut -d. -f2)
83
+ if [ "$PROJ_MAJOR" != "$core_MAJOR" ] || [ "$PROJ_MINOR" != "$core_MINOR" ]; then
84
+ # Major or minor mismatch: set version to match doc-detective-core major.minor.0
85
+ NEW_VERSION="$core_MAJOR.$core_MINOR.0"
86
+ npm version --no-git-tag-version "$NEW_VERSION"
87
+ else
88
+ # Only patch changed: bump patch
89
+ npm version patch --no-git-tag-version
90
+ fi
91
+ git add package.json package-lock.json
92
+ git commit -m "bump version to match doc-detective-core"
74
93
  git push
94
+ git tag "v$(node -p \"require('./package.json').version\")"
75
95
  git push --tags
76
- echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
96
+ echo "version=$(node -p \"require('./package.json').version\")" >> $GITHUB_OUTPUT
77
97
 
78
98
  - name: Create release
99
+ if: steps.commit.outputs.has_changes == 'true'
100
+ # Install GitHub CLI for fetching PRs and release notes
101
+ run: |
102
+ sudo apt-get update && sudo apt-get install -y gh jq
103
+
104
+ - name: Gather merged PRs since last release
105
+ id: merged_prs
106
+ run: |
107
+ # Get previous tag (before the new one)
108
+ PREV_TAG=$(git tag --sort=-creatordate | grep -v "v${{ steps.patch.outputs.version }}" | head -n1)
109
+ CURR_TAG="v${{ steps.patch.outputs.version }}"
110
+ echo "Previous tag: $PREV_TAG, Current tag: $CURR_TAG"
111
+ if [ -z "$PREV_TAG" ]; then
112
+ echo "No previous tag found. Skipping PR list."
113
+ echo "prs=No previous release found." >> $GITHUB_OUTPUT
114
+ else
115
+ PRS=$(gh pr list --state merged --search "merged:>=$(git log -1 --format=%aI $PREV_TAG)" --json number,title,url --jq '.[] | "- [#\(.number)](\(.url)): \(.title)"')
116
+ if [ -z "$PRS" ]; then
117
+ PRS=""
118
+ fi
119
+ echo "prs<<EOF" >> $GITHUB_OUTPUT
120
+ echo "$PRS" >> $GITHUB_OUTPUT
121
+ echo "EOF" >> $GITHUB_OUTPUT
122
+ fi
123
+
124
+ - name: Fetch doc-detective-core release notes
125
+ id: core_release
126
+ run: |
127
+ CORE_VERSION=${{ steps.version.outputs.version }}
128
+ # Remove ^ or ~ if present
129
+ CORE_VERSION_CLEAN=$(echo "$CORE_VERSION" | sed 's/^[^0-9]*//')
130
+ # Query GitHub API for release notes
131
+ RELEASE_INFO=$(gh release view "v$CORE_VERSION_CLEAN" --repo doc-detective/doc-detective-core --json body --jq .body || echo "No release notes found.")
132
+ echo "release_notes<<EOF" >> $GITHUB_OUTPUT
133
+ echo "$RELEASE_INFO" >> $GITHUB_OUTPUT
134
+ echo "EOF" >> $GITHUB_OUTPUT
135
+
136
+ - name: Create release with detailed notes
79
137
  if: steps.commit.outputs.has_changes == 'true'
80
138
  uses: softprops/action-gh-release@v2
81
139
  with:
82
- body: "Updated to doc-detective-core v${{ steps.patch.outputs.version }}."
140
+ body: |
141
+ # What's new
142
+
143
+ - Updated doc-detective-core to v${{ steps.patch.outputs.version }}:
144
+
145
+ ${{ steps.core_release.outputs.release_notes }}
146
+
147
+ ${{ steps.merged_prs.outputs.prs }}
83
148
  tag_name: "v${{ steps.patch.outputs.version }}"
84
149
  name: "v${{ steps.patch.outputs.version }}"
85
- generate_release_notes: true
150
+ generate_release_notes: false
86
151
  token: ${{ secrets.DD_DEP_UPDATE_TOKEN }}
87
152
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc-detective",
3
- "version": "3.0.17",
3
+ "version": "3.1.0-dev.2",
4
4
  "description": "Treat doc content as testable assertions to validate doc accuracy and product UX.",
5
5
  "bin": {
6
6
  "doc-detective": "src/index.js"
@@ -33,12 +33,12 @@
33
33
  "homepage": "https://github.com/doc-detective/doc-detective#readme",
34
34
  "dependencies": {
35
35
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
36
- "doc-detective-common": "^3.0.9",
37
- "doc-detective-core": "^3.0.18",
36
+ "doc-detective-common": "^3.1.0-dev.1",
37
+ "doc-detective-core": "^3.1.0-dev.2",
38
38
  "yargs": "^17.7.2"
39
39
  },
40
40
  "devDependencies": {
41
41
  "chai": "^5.2.0",
42
- "mocha": "^11.5.0"
42
+ "mocha": "^11.7.0"
43
43
  }
44
44
  }
package/reference.png ADDED
Binary file
package/src/index.js CHANGED
@@ -35,7 +35,7 @@ async function main(argv) {
35
35
  : null;
36
36
 
37
37
  // Set config
38
- config = await setConfig({ configPath: configPath, args: argv });
38
+ const config = await setConfig({ configPath: configPath, args: argv });
39
39
 
40
40
  // Run tests
41
41
  const output = config.output;
package/src/utils.js CHANGED
@@ -39,6 +39,11 @@ function setArgs(args) {
39
39
  "Detail level of logging events. Accepted values: silent, error, warning, info (default), debug",
40
40
  type: "string",
41
41
  })
42
+ .option("allow-unsafe", {
43
+ description:
44
+ "Allow execution of potentially unsafe tests",
45
+ type: "boolean",
46
+ })
42
47
  .help()
43
48
  .alias("help", "h").argv;
44
49
 
@@ -111,6 +116,9 @@ async function setConfig({ configPath, args }) {
111
116
  if (args.logLevel) {
112
117
  config.logLevel = args.logLevel;
113
118
  }
119
+ if (typeof args.allowUnsafe === "boolean") {
120
+ config.allowUnsafeTests = args.allowUnsafe;
121
+ }
114
122
  // Resolve paths
115
123
  config = await resolvePaths({
116
124
  config: config,
@@ -222,6 +230,10 @@ const reporters = {
222
230
  (contexts && contexts.fail > 0) ||
223
231
  (steps && steps.fail > 0);
224
232
 
233
+ // Any skipped overall?
234
+ const allSpecsSkipped =
235
+ specs && specs.pass === 0 && specs.fail === 0 && specs.skipped > 0;
236
+
225
237
  console.log(
226
238
  `\n${colors.bold}===== Doc Detective Results Summary =====${colors.reset}`
227
239
  );
@@ -230,7 +242,11 @@ const reporters = {
230
242
  if (specs) {
231
243
  console.log(`\n${colors.bold}Specs:${colors.reset}`);
232
244
  console.log(`Total: ${totalSpecs}`);
233
- console.log(`${colors.green}Passed: ${specs.pass}${colors.reset}`);
245
+ if (specs.pass > 0) {
246
+ console.log(`${colors.green}Passed: ${specs.pass}${colors.reset}`);
247
+ } else {
248
+ console.log(`Passed: ${specs.pass}`);
249
+ }
234
250
  console.log(
235
251
  `${specs.fail > 0 ? colors.red : colors.green}Failed: ${specs.fail}${
236
252
  colors.reset
@@ -240,14 +256,19 @@ const reporters = {
240
256
  console.log(
241
257
  `${colors.yellow}Warnings: ${specs.warning}${colors.reset}`
242
258
  );
243
- if (specs.skipped > 0) console.log(`Skipped: ${specs.skipped}`);
259
+ if (specs.skipped > 0)
260
+ console.log(`${colors.yellow}Skipped: ${specs.skipped}${colors.reset}`);
244
261
  }
245
262
 
246
263
  // Print tests summary if available
247
264
  if (tests) {
248
265
  console.log(`\n${colors.bold}Tests:${colors.reset}`);
249
266
  console.log(`Total: ${totalTests}`);
250
- console.log(`${colors.green}Passed: ${tests.pass}${colors.reset}`);
267
+ if (tests.pass > 0) {
268
+ console.log(`${colors.green}Passed: ${tests.pass}${colors.reset}`);
269
+ } else {
270
+ console.log(`Passed: ${tests.pass}`);
271
+ }
251
272
  console.log(
252
273
  `${tests.fail > 0 ? colors.red : colors.green}Failed: ${tests.fail}${
253
274
  colors.reset
@@ -257,14 +278,19 @@ const reporters = {
257
278
  console.log(
258
279
  `${colors.yellow}Warnings: ${tests.warning}${colors.reset}`
259
280
  );
260
- if (tests.skipped > 0) console.log(`Skipped: ${tests.skipped}`);
281
+ if (tests.skipped > 0)
282
+ console.log(`${colors.yellow}Skipped: ${tests.skipped}${colors.reset}`);
261
283
  }
262
284
 
263
285
  // Print contexts summary if available
264
286
  if (contexts) {
265
287
  console.log(`\n${colors.bold}Contexts:${colors.reset}`);
266
288
  console.log(`Total: ${totalContexts}`);
267
- console.log(`${colors.green}Passed: ${contexts.pass}${colors.reset}`);
289
+ if (contexts.pass > 0) {
290
+ console.log(`${colors.green}Passed: ${contexts.pass}${colors.reset}`);
291
+ } else {
292
+ console.log(`Passed: ${contexts.pass}`);
293
+ }
268
294
  console.log(
269
295
  `${contexts.fail > 0 ? colors.red : colors.green}Failed: ${
270
296
  contexts.fail
@@ -274,14 +300,19 @@ const reporters = {
274
300
  console.log(
275
301
  `${colors.yellow}Warnings: ${contexts.warning}${colors.reset}`
276
302
  );
277
- if (contexts.skipped > 0) console.log(`Skipped: ${contexts.skipped}`);
303
+ if (contexts.skipped > 0)
304
+ console.log(`${colors.yellow}Skipped: ${contexts.skipped}${colors.reset}`);
278
305
  }
279
306
 
280
307
  // Print steps summary if available
281
308
  if (steps) {
282
309
  console.log(`\n${colors.bold}Steps:${colors.reset}`);
283
310
  console.log(`Total: ${totalSteps}`);
284
- console.log(`${colors.green}Passed: ${steps.pass}${colors.reset}`);
311
+ if (steps.pass > 0) {
312
+ console.log(`${colors.green}Passed: ${steps.pass}${colors.reset}`);
313
+ } else {
314
+ console.log(`Passed: ${steps.pass}`);
315
+ }
285
316
  console.log(
286
317
  `${steps.fail > 0 ? colors.red : colors.green}Failed: ${steps.fail}${
287
318
  colors.reset
@@ -291,7 +322,13 @@ const reporters = {
291
322
  console.log(
292
323
  `${colors.yellow}Warnings: ${steps.warning}${colors.reset}`
293
324
  );
294
- if (steps.skipped > 0) console.log(`Skipped: ${steps.skipped}`);
325
+ if (steps.skipped > 0)
326
+ console.log(`${colors.yellow}Skipped: ${steps.skipped}${colors.reset}`);
327
+ }
328
+
329
+ // If all specs were skipped, call it out
330
+ if (allSpecsSkipped) {
331
+ console.log(`\n${colors.yellow}⚠️ All items were skipped. No specs passed or failed. ⚠️${colors.reset}`);
295
332
  }
296
333
 
297
334
  // If we have specs with failures, display them
@@ -306,7 +343,13 @@ const reporters = {
306
343
  const failedContexts = [];
307
344
  const failedSteps = [];
308
345
 
309
- // Process specs array to collect failures
346
+ // Collect skipped
347
+ const skippedSpecs = [];
348
+ const skippedTests = [];
349
+ const skippedContexts = [];
350
+ const skippedSteps = [];
351
+
352
+ // Process specs array to collect failures and skipped
310
353
  results.specs.forEach((spec, specIndex) => {
311
354
  // Check if spec has failed
312
355
  if (spec.result === "FAIL") {
@@ -315,6 +358,13 @@ const reporters = {
315
358
  id: spec.specId || `Spec ${specIndex + 1}`,
316
359
  });
317
360
  }
361
+ // Check if spec was skipped
362
+ if (spec.result === "SKIPPED") {
363
+ skippedSpecs.push({
364
+ index: specIndex,
365
+ id: spec.specId || `Spec ${specIndex + 1}`,
366
+ });
367
+ }
318
368
 
319
369
  // Process tests in this spec
320
370
  if (spec.tests && spec.tests.length > 0) {
@@ -328,6 +378,15 @@ const reporters = {
328
378
  id: test.testId || `Test ${testIndex + 1}`,
329
379
  });
330
380
  }
381
+ // Check if test was skipped
382
+ if (test.result === "SKIPPED") {
383
+ skippedTests.push({
384
+ specIndex,
385
+ testIndex,
386
+ specId: spec.specId || `Spec ${specIndex + 1}`,
387
+ id: test.testId || `Test ${testIndex + 1}`,
388
+ });
389
+ }
331
390
 
332
391
  // Process contexts in this test
333
392
  if (test.contexts && test.contexts.length > 0) {
@@ -349,6 +408,23 @@ const reporters = {
349
408
  : "unknown",
350
409
  });
351
410
  }
411
+ // Check if context was skipped
412
+ if (
413
+ context.result === "SKIPPED" ||
414
+ (context.result && context.result.status === "SKIPPED")
415
+ ) {
416
+ skippedContexts.push({
417
+ specIndex,
418
+ testIndex,
419
+ contextIndex,
420
+ specId: spec.specId || `Spec ${specIndex + 1}`,
421
+ testId: test.testId || `Test ${testIndex + 1}`,
422
+ platform: context.platform || "unknown",
423
+ browser: context.browser
424
+ ? context.browser.name
425
+ : "unknown",
426
+ });
427
+ }
352
428
 
353
429
  // Process steps in this context
354
430
  if (context.steps && context.steps.length > 0) {
@@ -370,6 +446,22 @@ const reporters = {
370
446
  error: step.resultDescription || "Unknown error",
371
447
  });
372
448
  }
449
+ // Check if step was skipped
450
+ if (step.result === "SKIPPED") {
451
+ skippedSteps.push({
452
+ specIndex,
453
+ testIndex,
454
+ contextIndex,
455
+ stepIndex,
456
+ specId: spec.specId || `Spec ${specIndex + 1}`,
457
+ testId: test.testId || `Test ${testIndex + 1}`,
458
+ platform: context.platform || "unknown",
459
+ browser: context.browser
460
+ ? context.browser.name
461
+ : "unknown",
462
+ stepId: step.stepId || `Step ${stepIndex + 1}`,
463
+ });
464
+ }
373
465
  });
374
466
  }
375
467
  });
@@ -419,7 +511,33 @@ const reporters = {
419
511
  console.log(` Error: ${item.error}`);
420
512
  });
421
513
  }
422
- } else if (!hasFailures) {
514
+
515
+ // Display skipped items in yellow
516
+ if (skippedSpecs.length > 0) {
517
+ console.log(`\n${colors.yellow}Skipped Specs:${colors.reset}`);
518
+ skippedSpecs.forEach((item, i) => {
519
+ console.log(`${colors.yellow}${i + 1}. ${item.id}${colors.reset}`);
520
+ });
521
+ }
522
+ if (skippedTests.length > 0) {
523
+ console.log(`\n${colors.yellow}Skipped Tests:${colors.reset}`);
524
+ skippedTests.forEach((item, i) => {
525
+ console.log(`${colors.yellow}${i + 1}. ${item.id} (from ${item.specId})${colors.reset}`);
526
+ });
527
+ }
528
+ if (skippedContexts.length > 0) {
529
+ console.log(`\n${colors.yellow}Skipped Contexts:${colors.reset}`);
530
+ skippedContexts.forEach((item, i) => {
531
+ console.log(`${colors.yellow}${i + 1}. ${item.platform}/${item.browser} (from ${item.testId})${colors.reset}`);
532
+ });
533
+ }
534
+ if (skippedSteps.length > 0) {
535
+ console.log(`\n${colors.yellow}Skipped Steps:${colors.reset}`);
536
+ skippedSteps.forEach((item, i) => {
537
+ console.log(`${colors.yellow}${i + 1}. ${item.platform}/${item.browser} - ${item.stepId}${colors.reset}`);
538
+ });
539
+ }
540
+ } else if (!hasFailures && !allSpecsSkipped) {
423
541
  // Celebration when all tests pass
424
542
  console.log(`\n${colors.green}🎉 All items passed! 🎉${colors.reset}`);
425
543
  }
@@ -60,6 +60,19 @@ describe("Util tests", function () {
60
60
  c: "config.json",
61
61
  },
62
62
  },
63
+ {
64
+ args: [
65
+ "node",
66
+ "runTests.js",
67
+ "--input",
68
+ "input.spec.json",
69
+ "--allow-unsafe",
70
+ ],
71
+ expected: {
72
+ i: "input.spec.json",
73
+ allowUnsafe: true,
74
+ },
75
+ },
63
76
  ];
64
77
  argSets.forEach((argSet) => {
65
78
  expect(setArgs(argSet.args)).to.deep.include(argSet.expected);
@@ -144,6 +157,20 @@ describe("Util tests", function () {
144
157
  output: process.cwd(),
145
158
  recursive: true,
146
159
  },
160
+ },
161
+ {
162
+ // allow-unsafe override
163
+ args: [
164
+ "node",
165
+ "runTests.js",
166
+ "--input",
167
+ "input.spec.json",
168
+ "--allow-unsafe",
169
+ ],
170
+ expected: {
171
+ input: [path.resolve(process.cwd(), "input.spec.json")],
172
+ allowUnsafeTests: true,
173
+ },
147
174
  }
148
175
  ];
149
176