@vardot/varbase-e2e 2.0.0
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/AGENTS.md +148 -0
- package/CLAUDE.md +544 -0
- package/README.md +22 -0
- package/bin/generate-reports.js +363 -0
- package/bin/init-varbase-e2e.js +330 -0
- package/bin/postinstall.js +26 -0
- package/cucumber.js +125 -0
- package/docs/00-quick-start.md +102 -0
- package/docs/01-getting-started.md +102 -0
- package/docs/02-bbr-smart-waits.md +77 -0
- package/docs/03-selector-registry.md +95 -0
- package/docs/04-step-reference.md +801 -0
- package/docs/05-web-first-assertions.md +91 -0
- package/docs/06-network-and-dialogs.md +83 -0
- package/docs/07-auth-state.md +75 -0
- package/docs/08-clock-mocking.md +59 -0
- package/docs/09-api-testing.md +114 -0
- package/docs/10-accessibility.md +167 -0
- package/docs/11-debugging.md +129 -0
- package/docs/12-ai-agent-guide.md +338 -0
- package/docs/13-faq.md +236 -0
- package/docs/14-recipes-cookbook.md +255 -0
- package/docs/15-tag-conventions.md +76 -0
- package/docs/16-ci-cd.md +90 -0
- package/docs/README.md +125 -0
- package/docs/advanced-screenshots/then-i-save-fullscreen-screenshot.md +36 -0
- package/docs/advanced-screenshots/then-i-save-width-x-height-screenshot.md +34 -0
- package/docs/advanced-screenshots/when-i-save-screenshot-name-filename.md +45 -0
- package/docs/advanced-screenshots.md +52 -0
- package/docs/advanced-selectors.md +18 -0
- package/docs/api-step-definitions.md +45 -0
- package/docs/global-settings.md +267 -0
- package/docs/install-varbase-e2e/ddev-varbase-e2e.md +52 -0
- package/docs/install-varbase-e2e.md +34 -0
- package/docs/overview.md +40 -0
- package/docs/step-definitions/given-i-am-anonymous-user.md +67 -0
- package/docs/step-definitions/given-i-am-homepage.md +68 -0
- package/docs/step-definitions/given-i-am-specific-page.md +72 -0
- package/docs/step-definitions/then-i-should-be.md +56 -0
- package/docs/step-definitions/then-i-should-see.md +62 -0
- package/docs/step-definitions/then-item-checkbox.md +54 -0
- package/docs/step-definitions/then-item-link-should-contain-url.md +84 -0
- package/docs/step-definitions/then-item-should-contain.md +67 -0
- package/docs/step-definitions/then-radio-button-value-should-be-selected.md +68 -0
- package/docs/step-definitions/then-response-status-code-should-be-number.md +69 -0
- package/docs/step-definitions/then-value-radio-button-selected.md +62 -0
- package/docs/step-definitions/when-i-attach-file-file-name-element.md +71 -0
- package/docs/step-definitions/when-i-check-checkbox.md +60 -0
- package/docs/step-definitions/when-i-click-link.md +51 -0
- package/docs/step-definitions/when-i-click-operation-text-row.md +71 -0
- package/docs/step-definitions/when-i-fill.md +59 -0
- package/docs/step-definitions/when-i-go-homepage.md +60 -0
- package/docs/step-definitions/when-i-go-specific-page.md +67 -0
- package/docs/step-definitions/when-i-move-backward-one-page.md +49 -0
- package/docs/step-definitions/when-i-move-forward-one-page.md +58 -0
- package/docs/step-definitions/when-i-press-button.md +58 -0
- package/docs/step-definitions/when-i-reload-page.md +51 -0
- package/docs/step-definitions/when-i-scroll.md +73 -0
- package/docs/step-definitions/when-i-select-option-select-list.md +53 -0
- package/docs/step-definitions/when-i-select-radio-button-value.md +62 -0
- package/docs/step-definitions/when-i-uncheck-checkbox.md +57 -0
- package/docs/step-definitions/when-i-wait-ajax-finish.md +64 -0
- package/docs/step-definitions/when-i-wait.md +62 -0
- package/docs/step-definitions.md +82 -0
- package/docs/steps/README.md +137 -0
- package/docs/steps/a11y.md +731 -0
- package/docs/steps/action.md +181 -0
- package/docs/steps/api.md +679 -0
- package/docs/steps/assertion.md +328 -0
- package/docs/steps/auth.md +108 -0
- package/docs/steps/clock.md +171 -0
- package/docs/steps/cookie.md +293 -0
- package/docs/steps/debug.md +52 -0
- package/docs/steps/dialog.md +226 -0
- package/docs/steps/drupal-canvas.md +414 -0
- package/docs/steps/drupal-ckeditor.md +118 -0
- package/docs/steps/drupal-core.md +688 -0
- package/docs/steps/drupal-layout-builder.md +437 -0
- package/docs/steps/drupal-media.md +107 -0
- package/docs/steps/drupal-moderation.md +81 -0
- package/docs/steps/drupal-paragraphs.md +36 -0
- package/docs/steps/element.md +455 -0
- package/docs/steps/field.md +648 -0
- package/docs/steps/file-download.md +235 -0
- package/docs/steps/form.md +344 -0
- package/docs/steps/iframe.md +248 -0
- package/docs/steps/input.md +220 -0
- package/docs/steps/javascript.md +111 -0
- package/docs/steps/keyboard.md +107 -0
- package/docs/steps/link.md +217 -0
- package/docs/steps/metatag.md +99 -0
- package/docs/steps/modal.md +232 -0
- package/docs/steps/navigation.md +275 -0
- package/docs/steps/network.md +284 -0
- package/docs/steps/path.md +203 -0
- package/docs/steps/response.md +102 -0
- package/docs/steps/responsive.md +139 -0
- package/docs/steps/rest.md +140 -0
- package/docs/steps/screenshot.md +211 -0
- package/docs/steps/scroll.md +266 -0
- package/docs/steps/selectors.md +848 -0
- package/docs/steps/storage.md +254 -0
- package/docs/steps/table.md +216 -0
- package/docs/steps/varbase.md +391 -0
- package/docs/steps/video.md +111 -0
- package/docs/steps/wait.md +553 -0
- package/docs/steps/web-first.md +289 -0
- package/docs/steps/xml.md +505 -0
- package/docs/steps/yaml.md +951 -0
- package/examples/a11y.html +31 -0
- package/examples/about-us.html +11 -0
- package/examples/account.html +32 -0
- package/examples/ajax-wait-examples.html +147 -0
- package/examples/contact-us.html +10 -0
- package/examples/cookies.html +10 -0
- package/examples/date.html +12 -0
- package/examples/dynamic-examples.html +498 -0
- package/examples/element.html +11 -0
- package/examples/example-api.json +28 -0
- package/examples/existing-page.html +11 -0
- package/examples/field.html +24 -0
- package/examples/index.html +37 -0
- package/examples/keyboard.html +11 -0
- package/examples/links.html +9 -0
- package/examples/modal.html +14 -0
- package/examples/path.html +3 -0
- package/examples/table.html +13 -0
- package/examples/test--modal-dialogs.html +252 -0
- package/examples/test--then--i-should--not--see-text-in-element.html +48 -0
- package/examples/test--then--i-should--see-text-in-element.html +48 -0
- package/examples/test--then--i-should--see-text-matching-pattern.html +31 -0
- package/examples/test--then--i-should-see-text-in-table-row.html +232 -0
- package/examples/test--then--the-checkbox-checked.html +68 -0
- package/examples/test--then--the-element-should_not-contain-cssproperty.html +47 -0
- package/examples/test--then--the-link-should-contain.html +21 -0
- package/examples/test--when--i-additionally-select.html +27 -0
- package/examples/test--when--i-attach-file-to-feild.html +50 -0
- package/examples/test--when--i-check-uncheck-checkbox.html +47 -0
- package/examples/test--when--i-click-link.html +18 -0
- package/examples/test--when--i-click-text-in-table-row.html +178 -0
- package/examples/test--when--i-fill-in.html +48 -0
- package/examples/test--when--i-press-button.html +31 -0
- package/examples/test--when--i-reload-page.html +27 -0
- package/examples/test--when--i-scroll-functionality.html +177 -0
- package/examples/test--when--i-scroll-left-right-functionality.html +149 -0
- package/examples/test--when--i-select-option-from-dropdownlist.html +35 -0
- package/examples/test--when--i-select-radio-button.html +95 -0
- package/examples/test--when-i-wait-max-of-time.html +39 -0
- package/examples/test--when-i-wait-page-until-is-loaded.html +47 -0
- package/examples/test--when-i-wait-specific-time.html +39 -0
- package/examples/test-acceptable-url-path.html +11 -0
- package/examples/video-demo.html +43 -0
- package/package.json +56 -0
- package/playwright.config.ts +39 -0
- package/tests/assets/test-document.pdf +14 -0
- package/tests/assets/vardot.png +0 -0
- package/tests/features/a11y.feature +39 -0
- package/tests/features/ajax-wait-examples.feature +24 -0
- package/tests/features/api-step-definitions-individual.feature +185 -0
- package/tests/features/complete-api-testing-examples.feature +205 -0
- package/tests/features/cookie.feature +13 -0
- package/tests/features/date.feature +11 -0
- package/tests/features/dynamic-content-examples.feature +156 -0
- package/tests/features/element.feature +16 -0
- package/tests/features/field.feature +25 -0
- package/tests/features/keyboard.feature +10 -0
- package/tests/features/link.feature +11 -0
- package/tests/features/modal-advanced-example.feature +54 -0
- package/tests/features/modal-basic-example.feature +42 -0
- package/tests/features/modal-error-handling-example.feature +37 -0
- package/tests/features/modal.feature +11 -0
- package/tests/features/path.feature +16 -0
- package/tests/features/response.feature +8 -0
- package/tests/features/responsive.feature +10 -0
- package/tests/features/table.feature +18 -0
- package/tests/features/test--given--i-am-an-anonymous-user.feature +10 -0
- package/tests/features/test--given--i-am-on-homepage.feature +16 -0
- package/tests/features/test--then--i-save-screenshot.feature +33 -0
- package/tests/features/test--then--i-see-locator.feature +320 -0
- package/tests/features/test--then--i-should--not--see-text-in-element.feature +13 -0
- package/tests/features/test--then--i-should--see-text-in-element-by-attr.feature +10 -0
- package/tests/features/test--then--i-should--see-text-in-element.feature +10 -0
- package/tests/features/test--then--i-should--see-text-matching-pattern-in-element.feature +13 -0
- package/tests/features/test--then--i-should--see-text-matching-pattern.feature +18 -0
- package/tests/features/test--then--i-should-be-on-page.feature +10 -0
- package/tests/features/test--then--i-should-be-on-the-homepage.feature +10 -0
- package/tests/features/test--then--i-should-not-see-an-element-by-attr.feature +8 -0
- package/tests/features/test--then--i-should-not-see-an-element.feature +8 -0
- package/tests/features/test--then--i-should-see-an-element-by-attr.feature +8 -0
- package/tests/features/test--then--i-should-see-an-element.feature +8 -0
- package/tests/features/test--then--i-should-see-n-elements.feature +24 -0
- package/tests/features/test--then--i-should-see-text-in-table-row.feature +96 -0
- package/tests/features/test--then--print-current-url-and-response.feature +21 -0
- package/tests/features/test--then--the-checkbox-is-checked.feature +18 -0
- package/tests/features/test--then--the-checkbox-should-be-checked.feature +16 -0
- package/tests/features/test--then--the-element-should-contain-cssproperty.feature +9 -0
- package/tests/features/test--then--the-element-should-not-contain-cssproperty.feature +10 -0
- package/tests/features/test--then--the-field-should-contain-value.feature +11 -0
- package/tests/features/test--then--the-response-should-contain.feature +11 -0
- package/tests/features/test--then--the-response-status-code-should-be.feature +31 -0
- package/tests/features/test--then--the-url-should-match.feature +7 -0
- package/tests/features/test--then-the-link-should-contain-by-attribute.feature +18 -0
- package/tests/features/test--then-the-link-should-contain.feature +7 -0
- package/tests/features/test--when--i-additionally-select.feature +30 -0
- package/tests/features/test--when--i-attach-file-to-feild.feature +9 -0
- package/tests/features/test--when--i-check-checkbox.feature +21 -0
- package/tests/features/test--when--i-click-link-by-attribute.feature +21 -0
- package/tests/features/test--when--i-click-link.feature +9 -0
- package/tests/features/test--when--i-click-text-in-table-row.feature +37 -0
- package/tests/features/test--when--i-fill-in-by-attr.feature +31 -0
- package/tests/features/test--when--i-fill-in-table-by-attr.feature +19 -0
- package/tests/features/test--when--i-fill-in.feature +32 -0
- package/tests/features/test--when--i-follow.feature +22 -0
- package/tests/features/test--when--i-go-to-homepage.feature +9 -0
- package/tests/features/test--when--i-move-forward-backward-one-page.feature +14 -0
- package/tests/features/test--when--i-press-button-by-attribute.feature +18 -0
- package/tests/features/test--when--i-press-button.feature +13 -0
- package/tests/features/test--when--i-reload-page.feature +11 -0
- package/tests/features/test--when--i-scroll-left-right.feature +48 -0
- package/tests/features/test--when--i-scroll.feature +48 -0
- package/tests/features/test--when--i-select-option-from-dropdownlist.feature +21 -0
- package/tests/features/test--when--i-select-radio-button.feature +37 -0
- package/tests/features/test--when--i-wait-page-is-loaded.feature +8 -0
- package/tests/features/test--when--i-wait-time.feature +21 -0
- package/tests/features/video.feature +18 -0
- package/tests/features/wait.feature +7 -0
- package/tests/features/yaml.feature +102 -0
- package/tests/selectors/_canonical-keys.json +113 -0
- package/tests/selectors/back-end-selectors.json +19 -0
- package/tests/selectors/cms-contentful-admin.json +35 -0
- package/tests/selectors/cms-craft-admin.json +39 -0
- package/tests/selectors/cms-drupal-cms-gin.json +56 -0
- package/tests/selectors/cms-drupal-core-claro.json +50 -0
- package/tests/selectors/cms-generic-admin.json +34 -0
- package/tests/selectors/cms-ghost-admin.json +34 -0
- package/tests/selectors/cms-joomla-admin.json +41 -0
- package/tests/selectors/cms-magento2-admin.json +32 -0
- package/tests/selectors/cms-prestashop-admin.json +38 -0
- package/tests/selectors/cms-shopify-admin.json +25 -0
- package/tests/selectors/cms-strapi-admin.json +42 -0
- package/tests/selectors/cms-typo3-admin.json +41 -0
- package/tests/selectors/cms-woocommerce-front.json +50 -0
- package/tests/selectors/cms-wordpress-admin.json +31 -0
- package/tests/selectors/framework-ant-design.json +80 -0
- package/tests/selectors/framework-bootstrap.json +86 -0
- package/tests/selectors/framework-bulma.json +74 -0
- package/tests/selectors/framework-chakra.json +58 -0
- package/tests/selectors/framework-foundation.json +51 -0
- package/tests/selectors/framework-material-ui.json +72 -0
- package/tests/selectors/framework-shadcn.json +51 -0
- package/tests/selectors/framework-tailwind.json +40 -0
- package/tests/selectors/framework-vuetify.json +61 -0
- package/tests/selectors/front-end-selectors.json +16 -0
- package/tests/selectors/homepage-selectors.json +13 -0
- package/tests/step-definitions/a11y.steps.js +800 -0
- package/tests/step-definitions/action.steps.js +167 -0
- package/tests/step-definitions/api.steps.js +732 -0
- package/tests/step-definitions/assertion.steps.js +352 -0
- package/tests/step-definitions/auth.steps.js +126 -0
- package/tests/step-definitions/clock.steps.js +128 -0
- package/tests/step-definitions/cookie.steps.js +216 -0
- package/tests/step-definitions/debug.steps.js +39 -0
- package/tests/step-definitions/dialog.steps.js +193 -0
- package/tests/step-definitions/drupal-canvas.steps.js +764 -0
- package/tests/step-definitions/drupal-ckeditor.steps.js +108 -0
- package/tests/step-definitions/drupal-core.steps.js +665 -0
- package/tests/step-definitions/drupal-helpers.js +371 -0
- package/tests/step-definitions/drupal-layout-builder.steps.js +466 -0
- package/tests/step-definitions/drupal-media.steps.js +99 -0
- package/tests/step-definitions/drupal-moderation.steps.js +71 -0
- package/tests/step-definitions/drupal-paragraphs.steps.js +50 -0
- package/tests/step-definitions/element.steps.js +356 -0
- package/tests/step-definitions/field.steps.js +653 -0
- package/tests/step-definitions/file-download.steps.js +211 -0
- package/tests/step-definitions/form.steps.js +333 -0
- package/tests/step-definitions/iframe.steps.js +228 -0
- package/tests/step-definitions/input.steps.js +202 -0
- package/tests/step-definitions/javascript.steps.js +232 -0
- package/tests/step-definitions/keyboard.steps.js +112 -0
- package/tests/step-definitions/link.steps.js +142 -0
- package/tests/step-definitions/metatag.steps.js +91 -0
- package/tests/step-definitions/modal.steps.js +244 -0
- package/tests/step-definitions/navigation.steps.js +218 -0
- package/tests/step-definitions/network.steps.js +280 -0
- package/tests/step-definitions/path.steps.js +141 -0
- package/tests/step-definitions/response.steps.js +98 -0
- package/tests/step-definitions/responsive.steps.js +125 -0
- package/tests/step-definitions/rest.steps.js +111 -0
- package/tests/step-definitions/screenshot.steps.js +423 -0
- package/tests/step-definitions/scroll.steps.js +189 -0
- package/tests/step-definitions/selectors.steps.js +1003 -0
- package/tests/step-definitions/storage.steps.js +194 -0
- package/tests/step-definitions/table.steps.js +181 -0
- package/tests/step-definitions/varbase-e2e.js +897 -0
- package/tests/step-definitions/varbase.steps.js +458 -0
- package/tests/step-definitions/video.steps.js +178 -0
- package/tests/step-definitions/wait.steps.js +400 -0
- package/tests/step-definitions/web-first.steps.js +298 -0
- package/tests/step-definitions/xml.steps.js +411 -0
- package/tests/step-definitions/yaml.steps.js +913 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,913 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { friendly } = require('./varbase-e2e');
|
|
4
|
+
|
|
5
|
+
// Parse and assert against YAML response bodies.
|
|
6
|
+
//
|
|
7
|
+
// Mirrors xml.steps.js where it makes sense (path-based existence / equality
|
|
8
|
+
// / contains / count / "namespace") and adds YAML-native concepts: multi-
|
|
9
|
+
// document streams (`---`), type-of assertions, numeric comparisons,
|
|
10
|
+
// array-of-objects matching, JSONPath / JMESPath queries, JSON-Schema
|
|
11
|
+
// validation, key-set assertions, diff vs. expected, and well-formedness.
|
|
12
|
+
//
|
|
13
|
+
// Path syntax for the simple `/a/b/c` form is JSON Pointer (RFC 6901)
|
|
14
|
+
// flavoured: numeric segments index sequences (`/items/0/name`). For richer
|
|
15
|
+
// queries use the dedicated JSONPath / JMESPath steps.
|
|
16
|
+
|
|
17
|
+
const { Given, Then, When } = require('@cucumber/cucumber');
|
|
18
|
+
const assert = require('assert');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
let YAML; try { YAML = require('js-yaml'); } catch { /* lazy */ }
|
|
23
|
+
let Ajv; let addFormats;
|
|
24
|
+
try { Ajv = require('ajv'); } catch { /* lazy */ }
|
|
25
|
+
try { addFormats = require('ajv-formats'); } catch { /* lazy */ }
|
|
26
|
+
|
|
27
|
+
function requireYaml() {
|
|
28
|
+
if (!YAML) throw friendly('YAML steps require js-yaml. Install with: npm i js-yaml');
|
|
29
|
+
return YAML;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function ensureLoaded(world) {
|
|
33
|
+
requireYaml();
|
|
34
|
+
if (world._yaml === undefined) throw friendly('No YAML response has been set.');
|
|
35
|
+
return world._yaml;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Active document index for multi-document streams.
|
|
39
|
+
function activeIndex(world) { return world._yamlDocIndex || 0; }
|
|
40
|
+
function activeDoc(world) {
|
|
41
|
+
const docs = world._yamlDocs;
|
|
42
|
+
if (Array.isArray(docs) && docs.length > 0) return docs[activeIndex(world)];
|
|
43
|
+
return world._yaml;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Walk a "/a/b/c" path. Numeric segments index arrays. Returns array
|
|
47
|
+
// of matches (0 or 1 entries) so call sites mirror xml's evalXPath contract.
|
|
48
|
+
function evalPath(doc, p) {
|
|
49
|
+
if (!p || p === '/') return [doc];
|
|
50
|
+
const parts = p.split('/').filter(Boolean);
|
|
51
|
+
let cur = doc;
|
|
52
|
+
for (const raw of parts) {
|
|
53
|
+
if (cur == null) return [];
|
|
54
|
+
const m = raw.match(/^([^\[]+)?(?:\[(\d+)\])?$/);
|
|
55
|
+
const key = m && m[1];
|
|
56
|
+
const idx = m && m[2] !== undefined ? parseInt(m[2], 10) : null;
|
|
57
|
+
if (key) {
|
|
58
|
+
if (typeof cur !== 'object' || !(key in cur)) return [];
|
|
59
|
+
cur = cur[key];
|
|
60
|
+
}
|
|
61
|
+
if (idx !== null) {
|
|
62
|
+
if (!Array.isArray(cur) || idx >= cur.length) return [];
|
|
63
|
+
cur = cur[idx];
|
|
64
|
+
}
|
|
65
|
+
if (!key && idx === null && /^\d+$/.test(raw)) {
|
|
66
|
+
const i = parseInt(raw, 10);
|
|
67
|
+
if (!Array.isArray(cur) || i >= cur.length) return [];
|
|
68
|
+
cur = cur[i];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return cur === undefined ? [] : [cur];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function nodeText(node) {
|
|
75
|
+
if (node === null || node === undefined) return '';
|
|
76
|
+
if (typeof node === 'string') return node;
|
|
77
|
+
if (typeof node === 'number' || typeof node === 'boolean') return String(node);
|
|
78
|
+
return YAML.dump(node).trim();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function nodeAttr(node, key) {
|
|
82
|
+
if (node && typeof node === 'object' && !Array.isArray(node) && key in node) {
|
|
83
|
+
return nodeText(node[key]);
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function nodeHasAttr(node, key) {
|
|
89
|
+
return node && typeof node === 'object' && !Array.isArray(node) && Object.prototype.hasOwnProperty.call(node, key);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function typeOfNode(node) {
|
|
93
|
+
if (node === null) return 'null';
|
|
94
|
+
if (Array.isArray(node)) return 'array';
|
|
95
|
+
const t = typeof node;
|
|
96
|
+
if (t === 'object') return 'object';
|
|
97
|
+
if (t === 'number') return Number.isInteger(node) ? 'integer' : 'number';
|
|
98
|
+
return t; // 'string' | 'boolean'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Loading
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Load YAML response content from a file under `tests/assets/`.
|
|
107
|
+
*
|
|
108
|
+
* Multi-document streams (`---`) are parsed via `loadAll`. The first document
|
|
109
|
+
* becomes the default; switch with `Given the active YAML document is N`.
|
|
110
|
+
*
|
|
111
|
+
* Example #1: Given the YAML response content from the file "config.yml"
|
|
112
|
+
* Example #2: Given the YAML response content from the file "openapi.yaml"
|
|
113
|
+
* Example #3: And the YAML response content from the file "users.yml"
|
|
114
|
+
* Example #4: Given the YAML response content from the file "k8s-deployment.yaml"
|
|
115
|
+
* Example #5: Given the YAML response content from the file "/tmp/sample.yml"
|
|
116
|
+
*
|
|
117
|
+
*/
|
|
118
|
+
Given('the YAML response content from the file {string}', async function (filename) {
|
|
119
|
+
requireYaml();
|
|
120
|
+
const p = path.isAbsolute(filename) ? filename : path.join(this.assetsFolder || './tests/assets', filename);
|
|
121
|
+
const content = fs.readFileSync(p, 'utf-8');
|
|
122
|
+
this._rawYamlResponse = content;
|
|
123
|
+
this._yamlDocs = YAML.loadAll(content);
|
|
124
|
+
this._yaml = this._yamlDocs[0];
|
|
125
|
+
this._yamlDocIndex = 0;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Set YAML response content inline from a Gherkin doc string. Supports
|
|
130
|
+
* multi-document streams.
|
|
131
|
+
*
|
|
132
|
+
* Example #1: Given the YAML response content is the following:
|
|
133
|
+
* """
|
|
134
|
+
* name: example
|
|
135
|
+
* version: 1.0.0
|
|
136
|
+
* """
|
|
137
|
+
* Example #2: Given the YAML response content is the following:
|
|
138
|
+
* """
|
|
139
|
+
* items:
|
|
140
|
+
* - id: 1
|
|
141
|
+
* title: Hello
|
|
142
|
+
* """
|
|
143
|
+
* Example #3: And the YAML response content is the following:
|
|
144
|
+
* """
|
|
145
|
+
* status: ok
|
|
146
|
+
* count: 5
|
|
147
|
+
* """
|
|
148
|
+
* Example #4: Given the YAML response content is the following:
|
|
149
|
+
* """
|
|
150
|
+
* apiVersion: v1
|
|
151
|
+
* kind: ConfigMap
|
|
152
|
+
* ---
|
|
153
|
+
* apiVersion: v1
|
|
154
|
+
* kind: Service
|
|
155
|
+
* """
|
|
156
|
+
* Example #5: Given the YAML response content is the following:
|
|
157
|
+
* """
|
|
158
|
+
* error:
|
|
159
|
+
* code: 404
|
|
160
|
+
* message: Not found
|
|
161
|
+
* """
|
|
162
|
+
*
|
|
163
|
+
*/
|
|
164
|
+
Given('the YAML response content is the following:', async function (docString) {
|
|
165
|
+
requireYaml();
|
|
166
|
+
this._rawYamlResponse = docString;
|
|
167
|
+
this._yamlDocs = YAML.loadAll(docString);
|
|
168
|
+
this._yaml = this._yamlDocs[0];
|
|
169
|
+
this._yamlDocIndex = 0;
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Switch the active document for subsequent assertions. Index is 1-based to
|
|
174
|
+
* match how Helm / `kubectl get -o yaml` users describe documents.
|
|
175
|
+
*
|
|
176
|
+
* Example #1: Given the active YAML document is 1
|
|
177
|
+
* Example #2: Given the active YAML document is 2
|
|
178
|
+
* Example #3: And the active YAML document is 3
|
|
179
|
+
* Example #4: Given the active YAML document is 1
|
|
180
|
+
* Then the YAML element "/kind" should be equal to "ConfigMap"
|
|
181
|
+
* Example #5: Given the active YAML document is 2
|
|
182
|
+
* Then the YAML element "/kind" should be equal to "Service"
|
|
183
|
+
*
|
|
184
|
+
*/
|
|
185
|
+
Given('the active YAML document is {int}', function (n) {
|
|
186
|
+
if (!this._yamlDocs) throw friendly('No YAML response has been set.');
|
|
187
|
+
const idx = n - 1;
|
|
188
|
+
if (idx < 0 || idx >= this._yamlDocs.length) {
|
|
189
|
+
throw friendly(`Document ${n} out of range (have ${this._yamlDocs.length}).`);
|
|
190
|
+
}
|
|
191
|
+
this._yamlDocIndex = idx;
|
|
192
|
+
this._yaml = this._yamlDocs[idx];
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Assert the multi-document stream has exactly N documents.
|
|
197
|
+
*
|
|
198
|
+
* Example #1: Then the YAML response should have 1 document
|
|
199
|
+
* Example #2: Then the YAML response should have 2 documents
|
|
200
|
+
* Example #3: And the YAML response should have 5 documents
|
|
201
|
+
* Example #4: Then the YAML response should have 0 documents
|
|
202
|
+
* Example #5: Then the YAML response should have 10 documents
|
|
203
|
+
*
|
|
204
|
+
*/
|
|
205
|
+
Then('the YAML response should have {int} document(s)', function (n) {
|
|
206
|
+
ensureLoaded(this);
|
|
207
|
+
const have = (this._yamlDocs || []).length;
|
|
208
|
+
assert.strictEqual(have, n, `Expected ${n} YAML documents, got ${have}.`);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// Format / well-formedness
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Assert the loaded response parses as YAML.
|
|
217
|
+
*
|
|
218
|
+
* Example #1: Then the response should be in YAML format
|
|
219
|
+
* Example #2: Given the YAML response content from the file "openapi.yaml"
|
|
220
|
+
* Then the response should be in YAML format
|
|
221
|
+
* Example #3: And the response should be in YAML format
|
|
222
|
+
* Example #4: Given the YAML response content is the following:
|
|
223
|
+
* """
|
|
224
|
+
* key: value
|
|
225
|
+
* """
|
|
226
|
+
* Then the response should be in YAML format
|
|
227
|
+
* Example #5: Then the response should be in YAML format
|
|
228
|
+
* And the YAML element "/key" should exist
|
|
229
|
+
*
|
|
230
|
+
*/
|
|
231
|
+
Then('the response should be in YAML format', async function () {
|
|
232
|
+
requireYaml();
|
|
233
|
+
assert.ok(this._rawYamlResponse, 'No YAML response content set.');
|
|
234
|
+
try { YAML.loadAll(this._rawYamlResponse); }
|
|
235
|
+
catch (e) { assert.fail(`Response is not valid YAML: ${e.message}`); }
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Assert the loaded response is NOT valid YAML.
|
|
240
|
+
*
|
|
241
|
+
* Example #1: Then the response should not be in YAML format
|
|
242
|
+
* Example #2: Given the YAML response content is the following:
|
|
243
|
+
* """
|
|
244
|
+
* <not> yaml </not>
|
|
245
|
+
* """
|
|
246
|
+
* Then the response should not be in YAML format
|
|
247
|
+
* Example #3: And the response should not be in YAML format
|
|
248
|
+
* Example #4: Given the YAML response content is the following:
|
|
249
|
+
* """
|
|
250
|
+
* key: : :
|
|
251
|
+
* """
|
|
252
|
+
* Then the response should not be in YAML format
|
|
253
|
+
* Example #5: Then the response should not be in YAML format
|
|
254
|
+
* And I print last YAML response
|
|
255
|
+
*
|
|
256
|
+
*/
|
|
257
|
+
Then('the response should not be in YAML format', async function () {
|
|
258
|
+
if (!this._rawYamlResponse || !YAML) return;
|
|
259
|
+
try { YAML.loadAll(this._rawYamlResponse); }
|
|
260
|
+
catch (e) { return; /* expected */ }
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Assert the YAML has no duplicate keys at any level. Uses js-yaml's
|
|
265
|
+
* `onWarning` hook (duplicates raise warnings under default schema).
|
|
266
|
+
*
|
|
267
|
+
* Example #1: Then the YAML should have no duplicate keys
|
|
268
|
+
* Example #2: Given the YAML response content is the following:
|
|
269
|
+
* """
|
|
270
|
+
* name: A
|
|
271
|
+
* version: 1
|
|
272
|
+
* """
|
|
273
|
+
* Then the YAML should have no duplicate keys
|
|
274
|
+
* Example #3: And the YAML should have no duplicate keys
|
|
275
|
+
* Example #4: Then the YAML should have no duplicate keys
|
|
276
|
+
* And the YAML element "/name" should be equal to "A"
|
|
277
|
+
* Example #5: Then the YAML should have no duplicate keys
|
|
278
|
+
*
|
|
279
|
+
*/
|
|
280
|
+
Then('the YAML should have no duplicate keys', function () {
|
|
281
|
+
requireYaml();
|
|
282
|
+
assert.ok(this._rawYamlResponse, 'No YAML response content set.');
|
|
283
|
+
const warnings = [];
|
|
284
|
+
YAML.loadAll(this._rawYamlResponse, undefined, { onWarning: (w) => warnings.push(w.message || String(w)) });
|
|
285
|
+
const dupes = warnings.filter((m) => /duplicat/i.test(m));
|
|
286
|
+
assert.strictEqual(dupes.length, 0, `Duplicate keys found:\n ${dupes.join('\n ')}`);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// ---------------------------------------------------------------------------
|
|
290
|
+
// Existence + equality + contains (path-based)
|
|
291
|
+
// ---------------------------------------------------------------------------
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Assert at least one YAML node matches a path.
|
|
295
|
+
*
|
|
296
|
+
* Example #1: Then the YAML element "/name" should exist
|
|
297
|
+
* Example #2: Then the YAML element "/items/0/title" should exist
|
|
298
|
+
* Example #3: And the YAML element "/error/code" should exist
|
|
299
|
+
* Example #4: Then the YAML element "/spec/replicas" should exist
|
|
300
|
+
* Example #5: Then the YAML element "/users/2/email" should exist
|
|
301
|
+
*
|
|
302
|
+
*/
|
|
303
|
+
Then('the YAML element {string} should exist', function (p) {
|
|
304
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
305
|
+
assert.ok(evalPath(doc, p).length > 0, `YAML element "${p}" not found.`);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Assert NO YAML node matches a path.
|
|
310
|
+
*
|
|
311
|
+
* Example #1: Then the YAML element "/missing" should not exist
|
|
312
|
+
* Example #2: Then the YAML element "/items/100" should not exist
|
|
313
|
+
* Example #3: And the YAML element "/legacy/field" should not exist
|
|
314
|
+
* Example #4: Then the YAML element "/spec/internal" should not exist
|
|
315
|
+
* Example #5: Then the YAML element "/error/refund" should not exist
|
|
316
|
+
*
|
|
317
|
+
*/
|
|
318
|
+
Then('the YAML element {string} should not exist', function (p) {
|
|
319
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
320
|
+
assert.strictEqual(evalPath(doc, p).length, 0, `YAML element "${p}" should not exist.`);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Assert a YAML node's scalar value equals an expected value.
|
|
325
|
+
*
|
|
326
|
+
* Example #1: Then the YAML element "/name" should be equal to "example"
|
|
327
|
+
* Example #2: Then the YAML element "/version" should be equal to "2.5.2"
|
|
328
|
+
* Example #3: And the YAML element "/items/0/title" should be equal to "Hello"
|
|
329
|
+
* Example #4: Then the YAML element "/error/code" should be equal to "404"
|
|
330
|
+
* Example #5: Then the YAML element "/status" should be equal to "ok"
|
|
331
|
+
*
|
|
332
|
+
*/
|
|
333
|
+
Then('the YAML element {string} should be equal to {string}', function (p, text) {
|
|
334
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
335
|
+
const nodes = evalPath(doc, p);
|
|
336
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
337
|
+
assert.strictEqual(nodeText(nodes[0]), text);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Assert a YAML node's scalar value is NOT equal to an expected value.
|
|
342
|
+
*
|
|
343
|
+
* Example #1: Then the YAML element "/name" should not be equal to "Other"
|
|
344
|
+
* Example #2: Then the YAML element "/version" should not be equal to "1.0.0"
|
|
345
|
+
* Example #3: And the YAML element "/items/0/title" should not be equal to "Bye"
|
|
346
|
+
* Example #4: Then the YAML element "/error/code" should not be equal to "200"
|
|
347
|
+
* Example #5: Then the YAML element "/status" should not be equal to "fail"
|
|
348
|
+
*
|
|
349
|
+
*/
|
|
350
|
+
Then('the YAML element {string} should not be equal to {string}', function (p, text) {
|
|
351
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
352
|
+
const nodes = evalPath(doc, p);
|
|
353
|
+
if (nodes.length === 0) return;
|
|
354
|
+
assert.notStrictEqual(nodeText(nodes[0]), text);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Assert a YAML node's serialised value contains a substring.
|
|
359
|
+
*
|
|
360
|
+
* Example #1: Then the YAML element "/name" should contain "Web"
|
|
361
|
+
* Example #2: Then the YAML element "/items/0/title" should contain "Hello"
|
|
362
|
+
* Example #3: And the YAML element "/spec" should contain "replicas"
|
|
363
|
+
* Example #4: Then the YAML element "/error/message" should contain "Not"
|
|
364
|
+
* Example #5: Then the YAML element "/status" should contain "ok"
|
|
365
|
+
*
|
|
366
|
+
*/
|
|
367
|
+
Then('the YAML element {string} should contain {string}', function (p, text) {
|
|
368
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
369
|
+
const nodes = evalPath(doc, p);
|
|
370
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
371
|
+
assert.ok(nodeText(nodes[0]).indexOf(text) !== -1);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Assert a YAML node's serialised value does NOT contain a substring.
|
|
376
|
+
*
|
|
377
|
+
* Example #1: Then the YAML element "/name" should not contain "Error"
|
|
378
|
+
* Example #2: Then the YAML element "/items/0/title" should not contain "fail"
|
|
379
|
+
* Example #3: And the YAML element "/spec" should not contain "deprecated"
|
|
380
|
+
* Example #4: Then the YAML element "/error/message" should not contain "OK"
|
|
381
|
+
* Example #5: Then the YAML element "/status" should not contain "fatal"
|
|
382
|
+
*
|
|
383
|
+
*/
|
|
384
|
+
Then('the YAML element {string} should not contain {string}', function (p, text) {
|
|
385
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
386
|
+
const nodes = evalPath(doc, p);
|
|
387
|
+
if (nodes.length === 0) return;
|
|
388
|
+
assert.ok(nodeText(nodes[0]).indexOf(text) === -1);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// ---------------------------------------------------------------------------
|
|
392
|
+
// Attribute (direct child key) variants — kept verbatim from prior version.
|
|
393
|
+
// ---------------------------------------------------------------------------
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Assert a YAML node has a direct child key.
|
|
397
|
+
*
|
|
398
|
+
* Example #1: Then the YAML attribute "id" on element "/items/0" should exist
|
|
399
|
+
* Example #2: Then the YAML attribute "kind" on element "/" should exist
|
|
400
|
+
* Example #3: And the YAML attribute "code" on element "/error" should exist
|
|
401
|
+
* Example #4: Then the YAML attribute "replicas" on element "/spec" should exist
|
|
402
|
+
* Example #5: Then the YAML attribute "email" on element "/users/0" should exist
|
|
403
|
+
*
|
|
404
|
+
*/
|
|
405
|
+
Then('the YAML attribute {string} on element {string} should exist', function (attr, p) {
|
|
406
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
407
|
+
const nodes = evalPath(doc, p);
|
|
408
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
409
|
+
assert.ok(nodeHasAttr(nodes[0], attr), `Key "${attr}" not present on "${p}".`);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Assert a YAML node does NOT have a direct child key.
|
|
414
|
+
*
|
|
415
|
+
* Example #1: Then the YAML attribute "deprecated" on element "/items/0" should not exist
|
|
416
|
+
* Example #2: Then the YAML attribute "secret" on element "/" should not exist
|
|
417
|
+
* Example #3: And the YAML attribute "internal" on element "/spec" should not exist
|
|
418
|
+
* Example #4: Then the YAML attribute "private" on element "/error" should not exist
|
|
419
|
+
* Example #5: Then the YAML attribute "_legacy" on element "/users/0" should not exist
|
|
420
|
+
*
|
|
421
|
+
*/
|
|
422
|
+
Then('the YAML attribute {string} on element {string} should not exist', function (attr, p) {
|
|
423
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
424
|
+
const nodes = evalPath(doc, p);
|
|
425
|
+
if (nodes.length === 0) return;
|
|
426
|
+
assert.ok(!nodeHasAttr(nodes[0], attr), `Key "${attr}" should not exist on "${p}".`);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Assert a YAML child key's value equals an expected value.
|
|
431
|
+
*
|
|
432
|
+
* Example #1: Then the YAML attribute "id" on element "/items/0" should be equal to "1"
|
|
433
|
+
* Example #2: Then the YAML attribute "kind" on element "/" should be equal to "ConfigMap"
|
|
434
|
+
* Example #3: And the YAML attribute "code" on element "/error" should be equal to "404"
|
|
435
|
+
* Example #4: Then the YAML attribute "replicas" on element "/spec" should be equal to "3"
|
|
436
|
+
* Example #5: Then the YAML attribute "version" on element "/" should be equal to "v1"
|
|
437
|
+
*
|
|
438
|
+
*/
|
|
439
|
+
Then('the YAML attribute {string} on element {string} should be equal to {string}', function (attr, p, text) {
|
|
440
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
441
|
+
const nodes = evalPath(doc, p);
|
|
442
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
443
|
+
assert.strictEqual(nodeAttr(nodes[0], attr), text);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Assert a YAML child key's value is NOT equal to an expected value.
|
|
448
|
+
*
|
|
449
|
+
* Example #1: Then the YAML attribute "id" on element "/items/0" should not be equal to "0"
|
|
450
|
+
* Example #2: Then the YAML attribute "kind" on element "/" should not be equal to "Secret"
|
|
451
|
+
* Example #3: And the YAML attribute "code" on element "/error" should not be equal to "200"
|
|
452
|
+
* Example #4: Then the YAML attribute "replicas" on element "/spec" should not be equal to "0"
|
|
453
|
+
* Example #5: Then the YAML attribute "version" on element "/" should not be equal to "v0"
|
|
454
|
+
*
|
|
455
|
+
*/
|
|
456
|
+
Then('the YAML attribute {string} on element {string} should not be equal to {string}', function (attr, p, text) {
|
|
457
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
458
|
+
const nodes = evalPath(doc, p);
|
|
459
|
+
if (nodes.length === 0) return;
|
|
460
|
+
assert.notStrictEqual(nodeAttr(nodes[0], attr), text);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Assert a YAML child key's serialised value contains a substring.
|
|
465
|
+
*
|
|
466
|
+
* Example #1: Then the YAML attribute "id" on element "/items/0" should contain "abc"
|
|
467
|
+
* Example #2: Then the YAML attribute "image" on element "/spec" should contain "nginx"
|
|
468
|
+
* Example #3: And the YAML attribute "kind" on element "/" should contain "Map"
|
|
469
|
+
* Example #4: Then the YAML attribute "version" on element "/" should contain "v"
|
|
470
|
+
* Example #5: Then the YAML attribute "code" on element "/error" should contain "4"
|
|
471
|
+
*
|
|
472
|
+
*/
|
|
473
|
+
Then('the YAML attribute {string} on element {string} should contain {string}', function (attr, p, text) {
|
|
474
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
475
|
+
const nodes = evalPath(doc, p);
|
|
476
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
477
|
+
assert.ok((nodeAttr(nodes[0], attr) || '').indexOf(text) !== -1);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Assert a YAML child key's serialised value does NOT contain a substring.
|
|
482
|
+
*
|
|
483
|
+
* Example #1: Then the YAML attribute "id" on element "/items/0" should not contain "old"
|
|
484
|
+
* Example #2: Then the YAML attribute "image" on element "/spec" should not contain "alpine"
|
|
485
|
+
* Example #3: And the YAML attribute "kind" on element "/" should not contain "Secret"
|
|
486
|
+
* Example #4: Then the YAML attribute "version" on element "/" should not contain "alpha"
|
|
487
|
+
* Example #5: Then the YAML attribute "code" on element "/error" should not contain "5"
|
|
488
|
+
*
|
|
489
|
+
*/
|
|
490
|
+
Then('the YAML attribute {string} on element {string} should not contain {string}', function (attr, p, text) {
|
|
491
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
492
|
+
const nodes = evalPath(doc, p);
|
|
493
|
+
if (nodes.length === 0) return;
|
|
494
|
+
assert.ok((nodeAttr(nodes[0], attr) || '').indexOf(text) === -1);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Assert a YAML sequence / mapping at a path has exactly N entries.
|
|
499
|
+
*
|
|
500
|
+
* Example #1: Then the YAML element "/items" should have 5 elements
|
|
501
|
+
* Example #2: Then the YAML element "/users" should have 3 elements
|
|
502
|
+
* Example #3: And the YAML element "/spec/containers" should have 1 element
|
|
503
|
+
* Example #4: Then the YAML element "/errors" should have 0 elements
|
|
504
|
+
* Example #5: Then the YAML element "/feed/entries" should have 10 elements
|
|
505
|
+
*
|
|
506
|
+
*/
|
|
507
|
+
Then('the YAML element {string} should have {int} element(s)', function (p, count) {
|
|
508
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
509
|
+
const nodes = evalPath(doc, p);
|
|
510
|
+
const node = nodes[0];
|
|
511
|
+
const len = Array.isArray(node) ? node.length : (node && typeof node === 'object' ? Object.keys(node).length : 0);
|
|
512
|
+
assert.strictEqual(len, count);
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// ---------------------------------------------------------------------------
|
|
516
|
+
// Type-of assertions
|
|
517
|
+
// ---------------------------------------------------------------------------
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Assert a YAML node's type. Accepts: string, integer, number, boolean,
|
|
521
|
+
* array, object, null.
|
|
522
|
+
*
|
|
523
|
+
* Example #1: Then the YAML value at "/spec/replicas" should be of type "integer"
|
|
524
|
+
* Example #2: Then the YAML value at "/metadata/name" should be of type "string"
|
|
525
|
+
* Example #3: And the YAML value at "/spec/containers" should be of type "array"
|
|
526
|
+
* Example #4: Then the YAML value at "/spec" should be of type "object"
|
|
527
|
+
* Example #5: Then the YAML value at "/spec/paused" should be of type "boolean"
|
|
528
|
+
*
|
|
529
|
+
*/
|
|
530
|
+
Then('the YAML value at {string} should be of type {string}', function (p, expected) {
|
|
531
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
532
|
+
const nodes = evalPath(doc, p);
|
|
533
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
534
|
+
const got = typeOfNode(nodes[0]);
|
|
535
|
+
// Allow "number" to match both number and integer.
|
|
536
|
+
if (expected === 'number') assert.ok(got === 'number' || got === 'integer', `Expected number, got ${got}.`);
|
|
537
|
+
else assert.strictEqual(got, expected, `Expected ${expected}, got ${got}.`);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Assert a YAML node is empty: empty string, empty array, empty object, or null.
|
|
542
|
+
*
|
|
543
|
+
* Example #1: Then the YAML value at "/labels" should be empty
|
|
544
|
+
* Example #2: Then the YAML value at "/items" should be empty
|
|
545
|
+
* Example #3: And the YAML value at "/error" should be empty
|
|
546
|
+
* Example #4: Then the YAML value at "/notes" should be empty
|
|
547
|
+
* Example #5: Then the YAML value at "/status/conditions" should be empty
|
|
548
|
+
*
|
|
549
|
+
*/
|
|
550
|
+
Then('the YAML value at {string} should be empty', function (p) {
|
|
551
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
552
|
+
const nodes = evalPath(doc, p);
|
|
553
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
554
|
+
const v = nodes[0];
|
|
555
|
+
const empty = v == null || v === '' || (Array.isArray(v) && v.length === 0)
|
|
556
|
+
|| (typeof v === 'object' && Object.keys(v).length === 0);
|
|
557
|
+
assert.ok(empty, `YAML value at "${p}" is not empty.`);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Assert a YAML node is non-empty.
|
|
562
|
+
*
|
|
563
|
+
* Example #1: Then the YAML value at "/items" should not be empty
|
|
564
|
+
* Example #2: Then the YAML value at "/spec/containers" should not be empty
|
|
565
|
+
* Example #3: And the YAML value at "/metadata/name" should not be empty
|
|
566
|
+
* Example #4: Then the YAML value at "/users" should not be empty
|
|
567
|
+
* Example #5: Then the YAML value at "/spec/replicas" should not be empty
|
|
568
|
+
*
|
|
569
|
+
*/
|
|
570
|
+
Then('the YAML value at {string} should not be empty', function (p) {
|
|
571
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
572
|
+
const nodes = evalPath(doc, p);
|
|
573
|
+
assert.ok(nodes.length > 0, `YAML element "${p}" not found.`);
|
|
574
|
+
const v = nodes[0];
|
|
575
|
+
const empty = v == null || v === '' || (Array.isArray(v) && v.length === 0)
|
|
576
|
+
|| (typeof v === 'object' && Object.keys(v).length === 0);
|
|
577
|
+
assert.ok(!empty, `YAML value at "${p}" is empty.`);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
// ---------------------------------------------------------------------------
|
|
581
|
+
// Numeric comparisons
|
|
582
|
+
// ---------------------------------------------------------------------------
|
|
583
|
+
|
|
584
|
+
function numAt(doc, p) {
|
|
585
|
+
const nodes = evalPath(doc, p);
|
|
586
|
+
if (nodes.length === 0) throw friendly(`YAML element "${p}" not found.`);
|
|
587
|
+
const v = nodes[0];
|
|
588
|
+
const n = typeof v === 'number' ? v : Number(v);
|
|
589
|
+
if (!Number.isFinite(n)) throw friendly(`YAML value at "${p}" is not numeric: ${v}`);
|
|
590
|
+
return n;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Assert a numeric YAML node is greater than a value.
|
|
595
|
+
*
|
|
596
|
+
* Example #1: Then the YAML value at "/spec/replicas" should be greater than 0
|
|
597
|
+
* Example #2: Then the YAML value at "/timeout" should be greater than 5
|
|
598
|
+
* Example #3: And the YAML value at "/spec/minReadySeconds" should be greater than 0
|
|
599
|
+
* Example #4: Then the YAML value at "/limits/cpu" should be greater than 100
|
|
600
|
+
* Example #5: Then the YAML value at "/version/major" should be greater than 1
|
|
601
|
+
*
|
|
602
|
+
*/
|
|
603
|
+
Then('the YAML value at {string} should be greater than {float}', function (p, n) {
|
|
604
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
605
|
+
assert.ok(numAt(doc, p) > n);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Assert a numeric YAML node is greater than or equal to a value.
|
|
610
|
+
*
|
|
611
|
+
* Example #1: Then the YAML value at "/spec/replicas" should be greater than or equal to 1
|
|
612
|
+
* Example #2: Then the YAML value at "/retries" should be greater than or equal to 0
|
|
613
|
+
* Example #3: And the YAML value at "/timeout" should be greater than or equal to 30
|
|
614
|
+
* Example #4: Then the YAML value at "/version/major" should be greater than or equal to 2
|
|
615
|
+
* Example #5: Then the YAML value at "/limits/cpu" should be greater than or equal to 250
|
|
616
|
+
*
|
|
617
|
+
*/
|
|
618
|
+
Then('the YAML value at {string} should be greater than or equal to {float}', function (p, n) {
|
|
619
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
620
|
+
assert.ok(numAt(doc, p) >= n);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Assert a numeric YAML node is less than a value.
|
|
625
|
+
*
|
|
626
|
+
* Example #1: Then the YAML value at "/spec/replicas" should be less than 100
|
|
627
|
+
* Example #2: Then the YAML value at "/error/code" should be less than 500
|
|
628
|
+
* Example #3: And the YAML value at "/timeout" should be less than 60
|
|
629
|
+
* Example #4: Then the YAML value at "/version/minor" should be less than 10
|
|
630
|
+
* Example #5: Then the YAML value at "/cost" should be less than 1000
|
|
631
|
+
*
|
|
632
|
+
*/
|
|
633
|
+
Then('the YAML value at {string} should be less than {float}', function (p, n) {
|
|
634
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
635
|
+
assert.ok(numAt(doc, p) < n);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Assert a numeric YAML node is less than or equal to a value.
|
|
640
|
+
*
|
|
641
|
+
* Example #1: Then the YAML value at "/spec/replicas" should be less than or equal to 10
|
|
642
|
+
* Example #2: Then the YAML value at "/retries" should be less than or equal to 5
|
|
643
|
+
* Example #3: And the YAML value at "/timeout" should be less than or equal to 60
|
|
644
|
+
* Example #4: Then the YAML value at "/error/code" should be less than or equal to 599
|
|
645
|
+
* Example #5: Then the YAML value at "/version/major" should be less than or equal to 3
|
|
646
|
+
*
|
|
647
|
+
*/
|
|
648
|
+
Then('the YAML value at {string} should be less than or equal to {float}', function (p, n) {
|
|
649
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
650
|
+
assert.ok(numAt(doc, p) <= n);
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Assert a numeric YAML node falls within an inclusive range.
|
|
655
|
+
*
|
|
656
|
+
* Example #1: Then the YAML value at "/spec/replicas" should be between 1 and 10
|
|
657
|
+
* Example #2: Then the YAML value at "/timeout" should be between 5 and 60
|
|
658
|
+
* Example #3: And the YAML value at "/error/code" should be between 400 and 499
|
|
659
|
+
* Example #4: Then the YAML value at "/cpu" should be between 100 and 1000
|
|
660
|
+
* Example #5: Then the YAML value at "/version/major" should be between 2 and 5
|
|
661
|
+
*
|
|
662
|
+
*/
|
|
663
|
+
Then('the YAML value at {string} should be between {float} and {float}', function (p, lo, hi) {
|
|
664
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
665
|
+
const v = numAt(doc, p);
|
|
666
|
+
assert.ok(v >= lo && v <= hi, `Value ${v} not in [${lo}, ${hi}].`);
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
// ---------------------------------------------------------------------------
|
|
670
|
+
// Array operations
|
|
671
|
+
// ---------------------------------------------------------------------------
|
|
672
|
+
|
|
673
|
+
function arrayAt(doc, p) {
|
|
674
|
+
const nodes = evalPath(doc, p);
|
|
675
|
+
if (nodes.length === 0) throw friendly(`YAML element "${p}" not found.`);
|
|
676
|
+
const v = nodes[0];
|
|
677
|
+
if (!Array.isArray(v)) throw friendly(`YAML value at "${p}" is not an array.`);
|
|
678
|
+
return v;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Assert an array contains an item where a sub-key has the expected value.
|
|
683
|
+
* Sub-key path is relative to each item; supports the same `/a/b[0]` syntax.
|
|
684
|
+
*
|
|
685
|
+
* Example #1: Then the YAML array at "/spec/containers" should contain an item where "/name" is "nginx"
|
|
686
|
+
* Example #2: Then the YAML array at "/items" should contain an item where "/kind" is "Service"
|
|
687
|
+
* Example #3: And the YAML array at "/users" should contain an item where "/email" is "alice@example.com"
|
|
688
|
+
* Example #4: Then the YAML array at "/rules" should contain an item where "/host" is "example.com"
|
|
689
|
+
* Example #5: Then the YAML array at "/spec/ports" should contain an item where "/port" is "443"
|
|
690
|
+
*
|
|
691
|
+
*/
|
|
692
|
+
Then('the YAML array at {string} should contain an item where {string} is {string}', function (p, sub, value) {
|
|
693
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
694
|
+
const arr = arrayAt(doc, p);
|
|
695
|
+
const found = arr.some((item) => {
|
|
696
|
+
const got = evalPath(item, sub)[0];
|
|
697
|
+
return nodeText(got) === value;
|
|
698
|
+
});
|
|
699
|
+
assert.ok(found, `Array at "${p}" has no item where "${sub}" is "${value}".`);
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Assert NO item in an array has a sub-key matching a value.
|
|
704
|
+
*
|
|
705
|
+
* Example #1: Then the YAML array at "/spec/containers" should contain no item where "/image" is "alpine:latest"
|
|
706
|
+
* Example #2: Then the YAML array at "/users" should contain no item where "/role" is "anonymous"
|
|
707
|
+
* Example #3: And the YAML array at "/rules" should contain no item where "/host" is "deprecated.example.com"
|
|
708
|
+
* Example #4: Then the YAML array at "/spec/env" should contain no item where "/name" is "DEBUG"
|
|
709
|
+
* Example #5: Then the YAML array at "/items" should contain no item where "/status" is "failed"
|
|
710
|
+
*
|
|
711
|
+
*/
|
|
712
|
+
Then('the YAML array at {string} should contain no item where {string} is {string}', function (p, sub, value) {
|
|
713
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
714
|
+
const arr = arrayAt(doc, p);
|
|
715
|
+
const found = arr.some((item) => nodeText(evalPath(item, sub)[0]) === value);
|
|
716
|
+
assert.ok(!found, `Array at "${p}" unexpectedly has item where "${sub}" is "${value}".`);
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Assert every item in an array has a non-null sub-key.
|
|
721
|
+
*
|
|
722
|
+
* Example #1: Then every item in "/spec/containers" should have key "image"
|
|
723
|
+
* Example #2: Then every item in "/users" should have key "email"
|
|
724
|
+
* Example #3: And every item in "/spec/ports" should have key "port"
|
|
725
|
+
* Example #4: Then every item in "/items" should have key "kind"
|
|
726
|
+
* Example #5: Then every item in "/spec/rules" should have key "host"
|
|
727
|
+
*
|
|
728
|
+
*/
|
|
729
|
+
Then('every item in {string} should have key {string}', function (p, key) {
|
|
730
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
731
|
+
const arr = arrayAt(doc, p);
|
|
732
|
+
const missing = arr.findIndex((item) => !nodeHasAttr(item, key));
|
|
733
|
+
assert.strictEqual(missing, -1, `Item at index ${missing} in "${p}" is missing key "${key}".`);
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
// ---------------------------------------------------------------------------
|
|
737
|
+
// Key-set assertions
|
|
738
|
+
// ---------------------------------------------------------------------------
|
|
739
|
+
|
|
740
|
+
function keysAt(doc, p) {
|
|
741
|
+
const nodes = evalPath(doc, p);
|
|
742
|
+
if (nodes.length === 0) throw friendly(`YAML element "${p}" not found.`);
|
|
743
|
+
const v = nodes[0];
|
|
744
|
+
if (typeof v !== 'object' || Array.isArray(v) || v === null) {
|
|
745
|
+
throw friendly(`YAML value at "${p}" is not a mapping.`);
|
|
746
|
+
}
|
|
747
|
+
return Object.keys(v);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Assert the keys at a path exactly match a comma-separated list (no extras).
|
|
752
|
+
*
|
|
753
|
+
* Example #1: Then the YAML keys at "/metadata" should be exactly "name, namespace, labels"
|
|
754
|
+
* Example #2: Then the YAML keys at "/spec" should be exactly "replicas, selector, template"
|
|
755
|
+
* Example #3: And the YAML keys at "/error" should be exactly "code, message"
|
|
756
|
+
* Example #4: Then the YAML keys at "/" should be exactly "apiVersion, kind, metadata, spec"
|
|
757
|
+
* Example #5: Then the YAML keys at "/users/0" should be exactly "id, name, email"
|
|
758
|
+
*
|
|
759
|
+
*/
|
|
760
|
+
Then('the YAML keys at {string} should be exactly {string}', function (p, csv) {
|
|
761
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
762
|
+
const got = keysAt(doc, p).sort();
|
|
763
|
+
const want = csv.split(',').map((s) => s.trim()).filter(Boolean).sort();
|
|
764
|
+
assert.deepStrictEqual(got, want);
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Assert every required key is present at a path (extras allowed).
|
|
769
|
+
*
|
|
770
|
+
* Example #1: Then the YAML at "/metadata" should have keys "name, namespace"
|
|
771
|
+
* Example #2: Then the YAML at "/spec" should have keys "replicas, selector"
|
|
772
|
+
* Example #3: And the YAML at "/" should have keys "apiVersion, kind"
|
|
773
|
+
* Example #4: Then the YAML at "/error" should have keys "code, message"
|
|
774
|
+
* Example #5: Then the YAML at "/users/0" should have keys "id, email"
|
|
775
|
+
*
|
|
776
|
+
*/
|
|
777
|
+
Then('the YAML at {string} should have keys {string}', function (p, csv) {
|
|
778
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
779
|
+
const got = new Set(keysAt(doc, p));
|
|
780
|
+
const want = csv.split(',').map((s) => s.trim()).filter(Boolean);
|
|
781
|
+
for (const k of want) assert.ok(got.has(k), `Missing key "${k}" at "${p}".`);
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
// ---------------------------------------------------------------------------
|
|
785
|
+
// JSON Schema validation
|
|
786
|
+
// ---------------------------------------------------------------------------
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Validate the active YAML document against a JSON Schema file. Bundles
|
|
790
|
+
* `ajv-formats` so schemas using `format: date-time`, `email`, `uri`, etc.
|
|
791
|
+
* work out of the box.
|
|
792
|
+
*
|
|
793
|
+
* Example #1: Then the YAML should match JSON Schema "schemas/deployment.json"
|
|
794
|
+
* Example #2: Then the YAML should match JSON Schema "tests/schemas/openapi-3.1.json"
|
|
795
|
+
* Example #3: And the YAML should match JSON Schema "schemas/configmap.json"
|
|
796
|
+
* Example #4: Then the YAML should match JSON Schema "schemas/github-workflow.json"
|
|
797
|
+
* Example #5: Then the YAML should match JSON Schema "/abs/path/to/schema.json"
|
|
798
|
+
*
|
|
799
|
+
*/
|
|
800
|
+
Then('the YAML should match JSON Schema {string}', function (schemaFile) {
|
|
801
|
+
if (!Ajv) throw friendly('Schema validation requires ajv. Install with: npm i ajv ajv-formats');
|
|
802
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
803
|
+
const p = path.isAbsolute(schemaFile) ? schemaFile : path.join(this.assetsFolder || './tests/assets', schemaFile);
|
|
804
|
+
const schema = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
805
|
+
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
806
|
+
if (addFormats) addFormats(ajv);
|
|
807
|
+
const validate = ajv.compile(schema);
|
|
808
|
+
const ok = validate(doc);
|
|
809
|
+
assert.ok(ok, `YAML failed schema validation:\n ${(validate.errors || []).map((e) => e.instancePath + ' ' + e.message).join('\n ')}`);
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// ---------------------------------------------------------------------------
|
|
813
|
+
// Diff vs expected
|
|
814
|
+
// ---------------------------------------------------------------------------
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Assert the active YAML document equals the contents of an expected file,
|
|
818
|
+
* after removing the listed JSON Pointer paths from both sides. Common
|
|
819
|
+
* use: ignoring volatile fields like `metadata.resourceVersion` or
|
|
820
|
+
* `status` when diffing Kubernetes manifests.
|
|
821
|
+
*
|
|
822
|
+
* Example #1: Then the YAML should equal the file "expected.yaml" ignoring keys "/metadata/resourceVersion"
|
|
823
|
+
* Example #2: Then the YAML should equal the file "expected.yaml" ignoring keys "/status, /metadata/uid"
|
|
824
|
+
* Example #3: And the YAML should equal the file "golden.yaml" ignoring keys "/metadata/creationTimestamp"
|
|
825
|
+
* Example #4: Then the YAML should equal the file "expected.yml" ignoring keys ""
|
|
826
|
+
* Example #5: Then the YAML should equal the file "tests/golden/deploy.yaml" ignoring keys "/status, /metadata/uid, /metadata/resourceVersion"
|
|
827
|
+
*
|
|
828
|
+
*/
|
|
829
|
+
Then('the YAML should equal the file {string} ignoring keys {string}', function (file, ignoreCsv) {
|
|
830
|
+
requireYaml();
|
|
831
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
832
|
+
const p = path.isAbsolute(file) ? file : path.join(this.assetsFolder || './tests/assets', file);
|
|
833
|
+
const expected = YAML.load(fs.readFileSync(p, 'utf-8'));
|
|
834
|
+
const ignore = ignoreCsv.split(',').map((s) => s.trim()).filter(Boolean);
|
|
835
|
+
const stripAt = (root, ptr) => {
|
|
836
|
+
const parts = ptr.split('/').filter(Boolean);
|
|
837
|
+
if (parts.length === 0) return;
|
|
838
|
+
const last = parts.pop();
|
|
839
|
+
let cur = root;
|
|
840
|
+
for (const part of parts) {
|
|
841
|
+
if (cur && typeof cur === 'object' && part in cur) cur = cur[part];
|
|
842
|
+
else return;
|
|
843
|
+
}
|
|
844
|
+
if (cur && typeof cur === 'object') delete cur[last];
|
|
845
|
+
};
|
|
846
|
+
const cloneA = JSON.parse(JSON.stringify(doc));
|
|
847
|
+
const cloneB = JSON.parse(JSON.stringify(expected));
|
|
848
|
+
for (const ptr of ignore) { stripAt(cloneA, ptr); stripAt(cloneB, ptr); }
|
|
849
|
+
assert.deepStrictEqual(cloneA, cloneB);
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
// ---------------------------------------------------------------------------
|
|
853
|
+
// Namespace + debug
|
|
854
|
+
// ---------------------------------------------------------------------------
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Assert the YAML document declares a namespace value (mirrors xml.steps.js).
|
|
858
|
+
* Checks top-level scalar values and falls back to a raw-text scan.
|
|
859
|
+
*
|
|
860
|
+
* Example #1: Then the YAML should use the namespace "v1"
|
|
861
|
+
* Example #2: Then the YAML should use the namespace "apps/v1"
|
|
862
|
+
* Example #3: And the YAML should use the namespace "kustomize.config.k8s.io/v1beta1"
|
|
863
|
+
* Example #4: Then the YAML should use the namespace "argoproj.io/v1alpha1"
|
|
864
|
+
* Example #5: Then the YAML should use the namespace "openapi: 3.0.3"
|
|
865
|
+
*
|
|
866
|
+
*/
|
|
867
|
+
Then('the YAML should use the namespace {string}', function (ns) {
|
|
868
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
869
|
+
if (doc && typeof doc === 'object') {
|
|
870
|
+
const values = Object.values(doc).map((v) => (v == null ? '' : String(v)));
|
|
871
|
+
if (values.includes(ns)) return;
|
|
872
|
+
}
|
|
873
|
+
assert.ok((this._rawYamlResponse || '').indexOf(ns) !== -1, `Namespace "${ns}" not declared.`);
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Assert the YAML document does NOT declare a namespace value.
|
|
878
|
+
*
|
|
879
|
+
* Example #1: Then the YAML should not use the namespace "v0"
|
|
880
|
+
* Example #2: Then the YAML should not use the namespace "internal/v1"
|
|
881
|
+
* Example #3: And the YAML should not use the namespace "legacy"
|
|
882
|
+
* Example #4: Then the YAML should not use the namespace "v0alpha"
|
|
883
|
+
* Example #5: Then the YAML should not use the namespace "deprecated"
|
|
884
|
+
*
|
|
885
|
+
*/
|
|
886
|
+
Then('the YAML should not use the namespace {string}', function (ns) {
|
|
887
|
+
const doc = activeDoc(this); ensureLoaded(this);
|
|
888
|
+
if (doc && typeof doc === 'object') {
|
|
889
|
+
const values = Object.values(doc).map((v) => (v == null ? '' : String(v)));
|
|
890
|
+
assert.ok(!values.includes(ns), `Namespace "${ns}" should not be declared.`);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
assert.ok((this._rawYamlResponse || '').indexOf(ns) === -1, `Namespace "${ns}" should not be declared.`);
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Print the most recently set raw YAML response to stdout (debug aid).
|
|
898
|
+
*
|
|
899
|
+
* Example #1: When I print last YAML response
|
|
900
|
+
* Example #2: When we print last YAML response
|
|
901
|
+
* Example #3: And I print last YAML response
|
|
902
|
+
* Example #4: Given the YAML response content is the following:
|
|
903
|
+
* """
|
|
904
|
+
* key: value
|
|
905
|
+
* """
|
|
906
|
+
* When I print last YAML response
|
|
907
|
+
* Example #5: When we send a REST "GET" request to "/api/config"
|
|
908
|
+
* And we print last YAML response
|
|
909
|
+
*
|
|
910
|
+
*/
|
|
911
|
+
When(/^(I |we )*print last YAML response$/, async function () {
|
|
912
|
+
console.log(this._rawYamlResponse || '(no response)');
|
|
913
|
+
});
|