@esimplicitylabs/katalyst-xspec 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/cli/init.cjs +111 -97
- package/cli/upgrade.cjs +63 -1
- package/dist/{chunk-ACAXOGKZ.js → chunk-UTTKW2SR.js} +106 -165
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -4
- package/dist/steps/index.d.ts +0 -9
- package/dist/steps/index.js +1 -1
- package/package.json +2 -2
- package/skills/katalyst-bdd-architecture/SKILL.md +10 -9
- package/skills/katalyst-bdd-architecture/references/adapters.md +1 -1
- package/skills/katalyst-bdd-architecture/references/custom-steps.md +15 -19
- package/skills/katalyst-bdd-create-test/SKILL.md +34 -29
- package/skills/katalyst-bdd-create-test/references/api-patterns.md +0 -15
- package/skills/katalyst-bdd-create-test/references/hybrid-patterns.md +1 -14
- package/skills/katalyst-bdd-create-test/references/tui-patterns.md +3 -27
- package/skills/katalyst-bdd-create-test/references/ui-patterns.md +0 -19
- package/skills/katalyst-bdd-quickstart/SKILL.md +57 -55
- package/skills/katalyst-bdd-step-reference/SKILL.md +15 -19
- package/skills/katalyst-bdd-step-reference/references/api-steps.md +1 -2
- package/skills/katalyst-bdd-step-reference/references/shared-steps.md +1 -5
- package/skills/katalyst-bdd-step-reference/references/tui-steps.md +7 -5
- package/skills/katalyst-bdd-step-reference/references/ui-steps.md +1 -2
- package/skills/katalyst-bdd-troubleshooting/SKILL.md +23 -24
|
@@ -93,23 +93,23 @@ function registerApiHttpSteps(test) {
|
|
|
93
93
|
world.lastContentType = result.contentType;
|
|
94
94
|
world.lastResponse = result.response;
|
|
95
95
|
}
|
|
96
|
-
When("I GET {string}",
|
|
96
|
+
When("I GET {string}", async ({ api, world }, path) => {
|
|
97
97
|
await send({ api, world }, "GET", path);
|
|
98
98
|
});
|
|
99
|
-
When("I DELETE {string}",
|
|
99
|
+
When("I DELETE {string}", async ({ api, world }, path) => {
|
|
100
100
|
await send({ api, world }, "DELETE", path);
|
|
101
101
|
});
|
|
102
|
-
When("I POST {string} with JSON body:",
|
|
102
|
+
When("I POST {string} with JSON body:", async ({ api, world }, path, docString) => {
|
|
103
103
|
const interpolated = interpolate(docString ?? "", world.vars);
|
|
104
104
|
const parsed = tryParseJson(interpolated) ?? interpolated;
|
|
105
105
|
await send({ api, world }, "POST", path, parsed);
|
|
106
106
|
});
|
|
107
|
-
When("I PATCH {string} with JSON body:",
|
|
107
|
+
When("I PATCH {string} with JSON body:", async ({ api, world }, path, docString) => {
|
|
108
108
|
const interpolated = interpolate(docString ?? "", world.vars);
|
|
109
109
|
const parsed = tryParseJson(interpolated) ?? interpolated;
|
|
110
110
|
await send({ api, world }, "PATCH", path, parsed);
|
|
111
111
|
});
|
|
112
|
-
When("I PUT {string} with JSON body:",
|
|
112
|
+
When("I PUT {string} with JSON body:", async ({ api, world }, path, docString) => {
|
|
113
113
|
const interpolated = interpolate(docString ?? "", world.vars);
|
|
114
114
|
const parsed = tryParseJson(interpolated) ?? interpolated;
|
|
115
115
|
await send({ api, world }, "PUT", path, parsed);
|
|
@@ -121,22 +121,22 @@ import { createBdd as createBdd2 } from "playwright-bdd";
|
|
|
121
121
|
import { expect as expect2 } from "@playwright/test";
|
|
122
122
|
function registerApiAssertionSteps(test) {
|
|
123
123
|
const { Then } = createBdd2(test);
|
|
124
|
-
Then("the response status should be {int}",
|
|
124
|
+
Then("the response status should be {int}", async ({ world }, code) => {
|
|
125
125
|
expect2(world.lastStatus, `Unexpected status. Body: ${world.lastText}`).toBe(code);
|
|
126
126
|
});
|
|
127
|
-
Then("the response should be a JSON array",
|
|
127
|
+
Then("the response should be a JSON array", async ({ world }) => {
|
|
128
128
|
expect2(Array.isArray(world.lastJson), `Expected JSON array. Body: ${world.lastText}`).toBe(true);
|
|
129
129
|
});
|
|
130
|
-
Then("the response should be a JSON object",
|
|
130
|
+
Then("the response should be a JSON object", async ({ world }) => {
|
|
131
131
|
const v = world.lastJson;
|
|
132
132
|
expect2(v !== null && typeof v === "object" && !Array.isArray(v), `Expected JSON object. Body: ${world.lastText}`).toBe(true);
|
|
133
133
|
});
|
|
134
|
-
Then("the value at {string} should equal {string}",
|
|
134
|
+
Then("the value at {string} should equal {string}", async ({ world }, path, expectedRaw) => {
|
|
135
135
|
const actual = selectPath(world.lastJson, path);
|
|
136
136
|
const expected = parseExpected(expectedRaw, world);
|
|
137
137
|
expect2(actual).toEqual(expected);
|
|
138
138
|
});
|
|
139
|
-
Then("I store the value at {string} as {string}",
|
|
139
|
+
Then("I store the value at {string} as {string}", async ({ world, cleanup }, path, varName) => {
|
|
140
140
|
const val = selectPath(world.lastJson, path);
|
|
141
141
|
world.vars[varName] = String(val);
|
|
142
142
|
cleanup.registerFromVar(world, varName, val, world.lastJson);
|
|
@@ -147,13 +147,13 @@ function registerApiAssertionSteps(test) {
|
|
|
147
147
|
import { createBdd as createBdd3 } from "playwright-bdd";
|
|
148
148
|
function registerApiAuthSteps(test) {
|
|
149
149
|
const { Given } = createBdd3(test);
|
|
150
|
-
Given("I am authenticated as an admin via API",
|
|
150
|
+
Given("I am authenticated as an admin via API", async ({ auth, world }) => {
|
|
151
151
|
await auth.apiLoginAsAdmin(world);
|
|
152
152
|
});
|
|
153
|
-
Given("I am authenticated as a user via API",
|
|
153
|
+
Given("I am authenticated as a user via API", async ({ auth, world }) => {
|
|
154
154
|
await auth.apiLoginAsUser(world);
|
|
155
155
|
});
|
|
156
|
-
Given("I set bearer token from variable {string}",
|
|
156
|
+
Given("I set bearer token from variable {string}", async ({ auth, world }, varName) => {
|
|
157
157
|
const token = world.vars[varName];
|
|
158
158
|
if (!token) throw new Error(`No token found in variable '${varName}'`);
|
|
159
159
|
auth.apiSetBearer(world, token);
|
|
@@ -164,7 +164,7 @@ function registerApiAuthSteps(test) {
|
|
|
164
164
|
import { createBdd as createBdd4 } from "playwright-bdd";
|
|
165
165
|
function registerHybridSteps(test) {
|
|
166
166
|
const { Given } = createBdd4(test);
|
|
167
|
-
Given("I navigate to interpolated path {string}",
|
|
167
|
+
Given("I navigate to interpolated path {string}", async ({ ui, world }, path) => {
|
|
168
168
|
await ui.goto(interpolate(path, world.vars));
|
|
169
169
|
});
|
|
170
170
|
}
|
|
@@ -332,42 +332,41 @@ async function expectElementAttribute(page, selector, attribute, value, options)
|
|
|
332
332
|
// src/steps/ui.basic.ts
|
|
333
333
|
function registerUiBasicSteps(test) {
|
|
334
334
|
const { Given, When, Then } = createBdd8(test);
|
|
335
|
-
Given("I navigate to {string}",
|
|
335
|
+
Given("I navigate to {string}", async ({ ui, world }, path) => {
|
|
336
336
|
await ui.goto(interpolate(path, world.vars));
|
|
337
337
|
});
|
|
338
|
-
When("I click the button {string}",
|
|
338
|
+
When("I click the button {string}", async ({ ui, world }, name) => {
|
|
339
339
|
await ui.clickButton(interpolate(name, world.vars));
|
|
340
340
|
});
|
|
341
|
-
When("I click the {string} button",
|
|
341
|
+
When("I click the {string} button", async ({ ui, world }, name) => {
|
|
342
342
|
await ui.clickButton(interpolate(name, world.vars));
|
|
343
343
|
});
|
|
344
|
-
When("I click the link {string}",
|
|
344
|
+
When("I click the link {string}", async ({ ui, world }, name) => {
|
|
345
345
|
await ui.clickLink(interpolate(name, world.vars));
|
|
346
346
|
});
|
|
347
|
-
When("I fill the placeholder {string} with {string}",
|
|
347
|
+
When("I fill the placeholder {string} with {string}", async ({ ui, world }, placeholder, value) => {
|
|
348
348
|
await ui.fillPlaceholder(interpolate(placeholder, world.vars), interpolate(value, world.vars));
|
|
349
349
|
});
|
|
350
|
-
When("I fill the field {string} with {string}",
|
|
350
|
+
When("I fill the field {string} with {string}", async ({ ui, world }, label, value) => {
|
|
351
351
|
await ui.fillLabel(interpolate(label, world.vars), interpolate(value, world.vars));
|
|
352
352
|
});
|
|
353
|
-
When("I fill in {string} with {string}",
|
|
353
|
+
When("I fill in {string} with {string}", async ({ ui, world }, label, value) => {
|
|
354
354
|
await ui.fillLabel(interpolate(label, world.vars), interpolate(value, world.vars));
|
|
355
355
|
});
|
|
356
|
-
When("I log in as admin in UI",
|
|
356
|
+
When("I log in as admin in UI", async ({ auth, world }) => {
|
|
357
357
|
await auth.uiLoginAsAdmin(world);
|
|
358
358
|
});
|
|
359
|
-
When("I log in as user in UI",
|
|
359
|
+
When("I log in as user in UI", async ({ auth, world }) => {
|
|
360
360
|
await auth.uiLoginAsUser(world);
|
|
361
361
|
});
|
|
362
|
-
When("I click the element {string}",
|
|
362
|
+
When("I click the element {string}", async ({ page, world }, selector) => {
|
|
363
363
|
await page.locator(interpolate(selector, world.vars)).click();
|
|
364
364
|
});
|
|
365
|
-
When("I select {string} from dropdown {string}",
|
|
365
|
+
When("I select {string} from dropdown {string}", async ({ page, world }, option, selector) => {
|
|
366
366
|
await page.locator(interpolate(selector, world.vars)).selectOption({ label: interpolate(option, world.vars) });
|
|
367
367
|
});
|
|
368
368
|
When(
|
|
369
369
|
"I set the file input {string} to a file named {string} with content {string}",
|
|
370
|
-
{ tags: "@ui or @hybrid" },
|
|
371
370
|
async ({ page, world }, selector, fileName, content) => {
|
|
372
371
|
await setFileInputContent(
|
|
373
372
|
page,
|
|
@@ -377,25 +376,25 @@ function registerUiBasicSteps(test) {
|
|
|
377
376
|
);
|
|
378
377
|
}
|
|
379
378
|
);
|
|
380
|
-
Then("I should see text {string}",
|
|
379
|
+
Then("I should see text {string}", async ({ ui, world }, text) => {
|
|
381
380
|
await ui.expectText(interpolate(text, world.vars));
|
|
382
381
|
});
|
|
383
|
-
Then("the URL should contain {string}",
|
|
382
|
+
Then("the URL should contain {string}", async ({ ui, world }, part) => {
|
|
384
383
|
await ui.expectUrlContains(interpolate(part, world.vars));
|
|
385
384
|
});
|
|
386
|
-
Then("I should be on page {string}",
|
|
385
|
+
Then("I should be on page {string}", async ({ ui, world }, path) => {
|
|
387
386
|
await ui.expectUrlContains(interpolate(path, world.vars));
|
|
388
387
|
});
|
|
389
|
-
Then("the element {string} should be visible",
|
|
388
|
+
Then("the element {string} should be visible", async ({ page, world }, selector) => {
|
|
390
389
|
await expect4(page.locator(interpolate(selector, world.vars))).toBeVisible();
|
|
391
390
|
});
|
|
392
|
-
Then("the element {string} should not be visible",
|
|
391
|
+
Then("the element {string} should not be visible", async ({ page, world }, selector) => {
|
|
393
392
|
await expect4(page.locator(interpolate(selector, world.vars))).not.toBeVisible();
|
|
394
393
|
});
|
|
395
|
-
Then("the element {string} should have value {string}",
|
|
394
|
+
Then("the element {string} should have value {string}", async ({ page, world }, selector, value) => {
|
|
396
395
|
await expect4(page.locator(interpolate(selector, world.vars))).toHaveValue(interpolate(value, world.vars));
|
|
397
396
|
});
|
|
398
|
-
Then("the element {string} should have attribute {string} equal to {string}",
|
|
397
|
+
Then("the element {string} should have attribute {string} equal to {string}", async ({ page, world }, selector, attribute, value) => {
|
|
399
398
|
await expectElementAttribute(
|
|
400
399
|
page,
|
|
401
400
|
interpolate(selector, world.vars),
|
|
@@ -403,10 +402,10 @@ function registerUiBasicSteps(test) {
|
|
|
403
402
|
interpolate(value, world.vars)
|
|
404
403
|
);
|
|
405
404
|
});
|
|
406
|
-
Then("the element {string} should be checked",
|
|
405
|
+
Then("the element {string} should be checked", async ({ page, world }, selector) => {
|
|
407
406
|
await expect4(page.locator(interpolate(selector, world.vars))).toBeChecked();
|
|
408
407
|
});
|
|
409
|
-
Then("the element {string} should not be checked",
|
|
408
|
+
Then("the element {string} should not be checked", async ({ page, world }, selector) => {
|
|
410
409
|
await expect4(page.locator(interpolate(selector, world.vars))).not.toBeChecked();
|
|
411
410
|
});
|
|
412
411
|
}
|
|
@@ -511,36 +510,35 @@ function parseRegex(input) {
|
|
|
511
510
|
}
|
|
512
511
|
function registerWizardSteps(test) {
|
|
513
512
|
const { Given, When, Then } = createBdd9(test);
|
|
514
|
-
Given("I open {string} page",
|
|
513
|
+
Given("I open {string} page", async ({ ui, world }, urlOrVar) => {
|
|
515
514
|
await ui.goto(resolveValue(urlOrVar, world));
|
|
516
515
|
});
|
|
517
|
-
Given("I open {string} in the browser",
|
|
516
|
+
Given("I open {string} in the browser", async ({ ui, world }, urlOrVar) => {
|
|
518
517
|
await ui.goto(resolveValue(urlOrVar, world));
|
|
519
518
|
});
|
|
520
|
-
When("I go back in the browser",
|
|
519
|
+
When("I go back in the browser", async ({ ui }) => {
|
|
521
520
|
await ui.goBack();
|
|
522
521
|
});
|
|
523
|
-
When("I save the current URL as {string}",
|
|
522
|
+
When("I save the current URL as {string}", async ({ ui, world }, varName) => {
|
|
524
523
|
world.vars[varName] = await ui.getCurrentUrl();
|
|
525
524
|
});
|
|
526
|
-
When("I save the current url as {string}",
|
|
525
|
+
When("I save the current url as {string}", async ({ ui, world }, varName) => {
|
|
527
526
|
world.vars[varName] = await ui.getCurrentUrl();
|
|
528
527
|
});
|
|
529
|
-
Then("I zoom to {string} in the browser",
|
|
528
|
+
Then("I zoom to {string} in the browser", async ({ ui, world }, scale) => {
|
|
530
529
|
await ui.zoomTo(parseNumber(scale, world));
|
|
531
530
|
});
|
|
532
|
-
When("I reload the page",
|
|
531
|
+
When("I reload the page", async ({ ui }) => {
|
|
533
532
|
await ui.reload();
|
|
534
533
|
});
|
|
535
|
-
Then("I wait {string} seconds",
|
|
534
|
+
Then("I wait {string} seconds", async ({ ui, world }, seconds) => {
|
|
536
535
|
await ui.waitSeconds(parseNumber(seconds, world));
|
|
537
536
|
});
|
|
538
|
-
Then("I wait for the page to load",
|
|
537
|
+
Then("I wait for the page to load", async ({ ui }) => {
|
|
539
538
|
await ui.waitForPageLoad();
|
|
540
539
|
});
|
|
541
540
|
When(
|
|
542
541
|
"I get a part of the URL based on {string} regular expression and save it as {string}",
|
|
543
|
-
{ tags: "@ui or @hybrid" },
|
|
544
542
|
async ({ ui, world }, regexString, varName) => {
|
|
545
543
|
const url = await ui.getCurrentUrl();
|
|
546
544
|
const regex = parseRegex(resolveValue(regexString, world));
|
|
@@ -549,7 +547,7 @@ function registerWizardSteps(test) {
|
|
|
549
547
|
world.vars[varName] = match[1] ?? match[0];
|
|
550
548
|
}
|
|
551
549
|
);
|
|
552
|
-
Then("I {string} {string}",
|
|
550
|
+
Then("I {string} {string}", async ({ ui, world }, action, value) => {
|
|
553
551
|
const verb = action.trim().toLowerCase();
|
|
554
552
|
const resolved = resolveValue(value, world);
|
|
555
553
|
if (verb === "type") {
|
|
@@ -564,7 +562,6 @@ function registerWizardSteps(test) {
|
|
|
564
562
|
});
|
|
565
563
|
When(
|
|
566
564
|
"I {string} the {string} element that contains {string}",
|
|
567
|
-
{ tags: "@ui or @hybrid" },
|
|
568
565
|
async ({ ui, world }, clickMode, elementType, text) => {
|
|
569
566
|
await ui.clickElementThatContains(
|
|
570
567
|
asClickMode(resolveValue(clickMode, world)),
|
|
@@ -575,7 +572,6 @@ function registerWizardSteps(test) {
|
|
|
575
572
|
);
|
|
576
573
|
When(
|
|
577
574
|
"I {string} the {string} element with {string} {string}",
|
|
578
|
-
{ tags: "@ui or @hybrid" },
|
|
579
575
|
async ({ ui, world }, clickMode, ordinal, text, method) => {
|
|
580
576
|
await ui.clickElementWith(
|
|
581
577
|
asClickMode(resolveValue(clickMode, world)),
|
|
@@ -585,12 +581,11 @@ function registerWizardSteps(test) {
|
|
|
585
581
|
);
|
|
586
582
|
}
|
|
587
583
|
);
|
|
588
|
-
When("I click on the top left corner of the page",
|
|
584
|
+
When("I click on the top left corner of the page", async ({ page }) => {
|
|
589
585
|
await page.mouse.click(0, 0);
|
|
590
586
|
});
|
|
591
587
|
When(
|
|
592
588
|
"If its visible, I {string} the {string} element with {string} {string}",
|
|
593
|
-
{ tags: "@ui or @hybrid" },
|
|
594
589
|
async ({ page, ui, world }, clickMode, ordinal, text, method) => {
|
|
595
590
|
const idx = parseOrdinalIndex(ordinal, world);
|
|
596
591
|
const resolvedText = resolveValue(text, world);
|
|
@@ -601,12 +596,11 @@ function registerWizardSteps(test) {
|
|
|
601
596
|
await ui.clickElementWith(asClickMode(resolveValue(clickMode, world)), ordinal, resolvedText, resolvedMethod);
|
|
602
597
|
}
|
|
603
598
|
);
|
|
604
|
-
Then("I fill {string} into the {string} dropdown",
|
|
599
|
+
Then("I fill {string} into the {string} dropdown", async ({ ui, world }, value, label) => {
|
|
605
600
|
await ui.fillDropdown(resolveValue(value, world), resolveValue(label, world));
|
|
606
601
|
});
|
|
607
602
|
When(
|
|
608
603
|
"I {string} {string} in the {string} element with {string} {string}",
|
|
609
|
-
{ tags: "@ui or @hybrid" },
|
|
610
604
|
async ({ ui, world }, action, value, ordinal, text, method) => {
|
|
611
605
|
await ui.inputInElement(
|
|
612
606
|
asInputMode(resolveValue(action, world)),
|
|
@@ -619,33 +613,30 @@ function registerWizardSteps(test) {
|
|
|
619
613
|
);
|
|
620
614
|
Then(
|
|
621
615
|
"I verify if a new tab which URL {string} {string} opens",
|
|
622
|
-
{ tags: "@ui or @hybrid" },
|
|
623
616
|
async ({ ui, world }, mode, expected) => {
|
|
624
617
|
await ui.expectNewTabUrl(asUrlAssertMode(resolveValue(mode, world)), resolveValue(expected, world));
|
|
625
618
|
}
|
|
626
619
|
);
|
|
627
620
|
Then(
|
|
628
621
|
"I verify if a new tab which url {string} {string} opens",
|
|
629
|
-
{ tags: "@ui or @hybrid" },
|
|
630
622
|
async ({ ui, world }, mode, expected) => {
|
|
631
623
|
await ui.expectNewTabUrl(asUrlAssertMode(resolveValue(mode, world)), resolveValue(expected, world));
|
|
632
624
|
}
|
|
633
625
|
);
|
|
634
|
-
Then("I verify if the URL {string} {string}",
|
|
626
|
+
Then("I verify if the URL {string} {string}", async ({ ui, world }, mode, expected) => {
|
|
635
627
|
await ui.expectUrl(asUrlAssertMode(resolveValue(mode, world)), resolveValue(expected, world));
|
|
636
628
|
});
|
|
637
|
-
Then("I verify if the url {string} {string}",
|
|
629
|
+
Then("I verify if the url {string} {string}", async ({ ui, world }, mode, expected) => {
|
|
638
630
|
await ui.expectUrl(asUrlAssertMode(resolveValue(mode, world)), resolveValue(expected, world));
|
|
639
631
|
});
|
|
640
|
-
Then("I verify if the URL {string} {string} opens",
|
|
632
|
+
Then("I verify if the URL {string} {string} opens", async ({ ui, world }, mode, expected) => {
|
|
641
633
|
await ui.expectUrl(asUrlAssertMode(resolveValue(mode, world)), resolveValue(expected, world));
|
|
642
634
|
});
|
|
643
|
-
Then("I verify if the url {string} {string} opens",
|
|
635
|
+
Then("I verify if the url {string} {string} opens", async ({ ui, world }, mode, expected) => {
|
|
644
636
|
await ui.expectUrl(asUrlAssertMode(resolveValue(mode, world)), resolveValue(expected, world));
|
|
645
637
|
});
|
|
646
638
|
Then(
|
|
647
639
|
"I verify that a {string} element with {string} text {string} visible",
|
|
648
|
-
{ tags: "@ui or @hybrid" },
|
|
649
640
|
async ({ ui, world }, elementType, text, assertion) => {
|
|
650
641
|
const normalized = resolveValue(assertion, world).trim().toLowerCase();
|
|
651
642
|
const shouldBeVisible = normalized === "is";
|
|
@@ -657,7 +648,6 @@ function registerWizardSteps(test) {
|
|
|
657
648
|
);
|
|
658
649
|
Then(
|
|
659
650
|
"I verify that {string} element with {string} {string} is {string}",
|
|
660
|
-
{ tags: "@ui or @hybrid" },
|
|
661
651
|
async ({ ui, world }, ordinal, text, method, state) => {
|
|
662
652
|
await ui.expectElementState(
|
|
663
653
|
resolveValue(ordinal, world),
|
|
@@ -669,7 +659,6 @@ function registerWizardSteps(test) {
|
|
|
669
659
|
);
|
|
670
660
|
Then(
|
|
671
661
|
"I verify that {string} element with {string} {string} becomes {string} during {string} seconds",
|
|
672
|
-
{ tags: "@ui or @hybrid" },
|
|
673
662
|
async ({ ui, world }, ordinal, text, method, state, seconds) => {
|
|
674
663
|
await ui.expectElementStateWithin(
|
|
675
664
|
resolveValue(ordinal, world),
|
|
@@ -688,7 +677,6 @@ function registerFormSteps(test) {
|
|
|
688
677
|
const { Given, When } = createBdd10(test);
|
|
689
678
|
When(
|
|
690
679
|
"I fill the form:",
|
|
691
|
-
{ tags: "@ui or @hybrid" },
|
|
692
680
|
async ({ ui, world }, dataTable) => {
|
|
693
681
|
const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
|
|
694
682
|
field: row[0],
|
|
@@ -703,7 +691,6 @@ function registerFormSteps(test) {
|
|
|
703
691
|
);
|
|
704
692
|
When(
|
|
705
693
|
"I fill the form with {string} locators:",
|
|
706
|
-
{ tags: "@ui or @hybrid" },
|
|
707
694
|
async ({ ui, world }, locatorMethod, dataTable) => {
|
|
708
695
|
const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
|
|
709
696
|
field: row[0],
|
|
@@ -718,7 +705,6 @@ function registerFormSteps(test) {
|
|
|
718
705
|
);
|
|
719
706
|
When(
|
|
720
707
|
"I fill and submit the form:",
|
|
721
|
-
{ tags: "@ui or @hybrid" },
|
|
722
708
|
async ({ ui, world }, dataTable) => {
|
|
723
709
|
const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
|
|
724
710
|
field: row[0],
|
|
@@ -734,7 +720,6 @@ function registerFormSteps(test) {
|
|
|
734
720
|
);
|
|
735
721
|
Given(
|
|
736
722
|
"I clear and fill the form:",
|
|
737
|
-
{ tags: "@ui or @hybrid" },
|
|
738
723
|
async ({ page, world }, dataTable) => {
|
|
739
724
|
const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
|
|
740
725
|
field: row[0],
|
|
@@ -757,7 +742,6 @@ function registerDebugSteps(test) {
|
|
|
757
742
|
const { When, Then } = createBdd11(test);
|
|
758
743
|
When(
|
|
759
744
|
"I capture the page HTML as {string}",
|
|
760
|
-
{ tags: "@ui or @hybrid" },
|
|
761
745
|
async ({ page, world }, varName) => {
|
|
762
746
|
const content = await page.content();
|
|
763
747
|
world.vars[varName] = content;
|
|
@@ -765,14 +749,12 @@ function registerDebugSteps(test) {
|
|
|
765
749
|
);
|
|
766
750
|
Then(
|
|
767
751
|
"I log the current URL",
|
|
768
|
-
{ tags: "@ui or @hybrid" },
|
|
769
752
|
async ({ page }) => {
|
|
770
753
|
console.log(`[DEBUG] Current URL: ${page.url()}`);
|
|
771
754
|
}
|
|
772
755
|
);
|
|
773
756
|
Then(
|
|
774
757
|
"I log the page title",
|
|
775
|
-
{ tags: "@ui or @hybrid" },
|
|
776
758
|
async ({ page }) => {
|
|
777
759
|
const title = await page.title();
|
|
778
760
|
console.log(`[DEBUG] Page title: ${title}`);
|
|
@@ -780,7 +762,6 @@ function registerDebugSteps(test) {
|
|
|
780
762
|
);
|
|
781
763
|
When(
|
|
782
764
|
"I save a screenshot as {string}",
|
|
783
|
-
{ tags: "@ui or @hybrid" },
|
|
784
765
|
async ({ page, world }, filename) => {
|
|
785
766
|
const resolvedFilename = interpolate(filename, world.vars);
|
|
786
767
|
await page.screenshot({ path: resolvedFilename });
|
|
@@ -789,7 +770,6 @@ function registerDebugSteps(test) {
|
|
|
789
770
|
);
|
|
790
771
|
When(
|
|
791
772
|
"I save a full page screenshot as {string}",
|
|
792
|
-
{ tags: "@ui or @hybrid" },
|
|
793
773
|
async ({ page, world }, filename) => {
|
|
794
774
|
const resolvedFilename = interpolate(filename, world.vars);
|
|
795
775
|
await page.screenshot({ path: resolvedFilename, fullPage: true });
|
|
@@ -798,7 +778,6 @@ function registerDebugSteps(test) {
|
|
|
798
778
|
);
|
|
799
779
|
When(
|
|
800
780
|
"I pause for debugging",
|
|
801
|
-
{ tags: "@ui or @hybrid" },
|
|
802
781
|
async ({ page }) => {
|
|
803
782
|
console.log('[DEBUG] Pausing for debugging. Press "Resume" in Playwright Inspector to continue.');
|
|
804
783
|
await page.pause();
|
|
@@ -806,7 +785,6 @@ function registerDebugSteps(test) {
|
|
|
806
785
|
);
|
|
807
786
|
Then(
|
|
808
787
|
"I print visible text",
|
|
809
|
-
{ tags: "@ui or @hybrid" },
|
|
810
788
|
async ({ page }) => {
|
|
811
789
|
const text = await page.innerText("body");
|
|
812
790
|
const truncated = text.length > 2e3 ? `${text.substring(0, 2e3)}...(truncated)` : text;
|
|
@@ -816,7 +794,6 @@ ${truncated}`);
|
|
|
816
794
|
);
|
|
817
795
|
Then(
|
|
818
796
|
"I count elements matching {string}",
|
|
819
|
-
{ tags: "@ui or @hybrid" },
|
|
820
797
|
async ({ page, world }, selector) => {
|
|
821
798
|
const resolvedSelector = interpolate(selector, world.vars);
|
|
822
799
|
const count = await page.locator(resolvedSelector).count();
|
|
@@ -825,7 +802,6 @@ ${truncated}`);
|
|
|
825
802
|
);
|
|
826
803
|
Then(
|
|
827
804
|
"I print browser console messages",
|
|
828
|
-
{ tags: "@ui or @hybrid" },
|
|
829
805
|
async ({ page }) => {
|
|
830
806
|
console.log("[DEBUG] Browser console messages will be captured from this point.");
|
|
831
807
|
page.on("console", (msg) => {
|
|
@@ -835,7 +811,6 @@ ${truncated}`);
|
|
|
835
811
|
);
|
|
836
812
|
When(
|
|
837
813
|
"I capture viewport size",
|
|
838
|
-
{ tags: "@ui or @hybrid" },
|
|
839
814
|
async ({ page, world }) => {
|
|
840
815
|
const viewport = page.viewportSize();
|
|
841
816
|
if (viewport) {
|
|
@@ -849,7 +824,6 @@ ${truncated}`);
|
|
|
849
824
|
);
|
|
850
825
|
Then(
|
|
851
826
|
"I log all cookies",
|
|
852
|
-
{ tags: "@ui or @hybrid" },
|
|
853
827
|
async ({ page }) => {
|
|
854
828
|
const context = page.context();
|
|
855
829
|
const cookies = await context.cookies();
|
|
@@ -861,7 +835,6 @@ ${truncated}`);
|
|
|
861
835
|
);
|
|
862
836
|
Then(
|
|
863
837
|
"I log localStorage",
|
|
864
|
-
{ tags: "@ui or @hybrid" },
|
|
865
838
|
async ({ page }) => {
|
|
866
839
|
const storage = await page.evaluate(() => {
|
|
867
840
|
const items = {};
|
|
@@ -882,7 +855,6 @@ ${truncated}`);
|
|
|
882
855
|
);
|
|
883
856
|
When(
|
|
884
857
|
"I highlight element {string}",
|
|
885
|
-
{ tags: "@ui or @hybrid" },
|
|
886
858
|
async ({ page, world }, selector) => {
|
|
887
859
|
const resolvedSelector = interpolate(selector, world.vars);
|
|
888
860
|
await page.evaluate((sel) => {
|
|
@@ -904,7 +876,6 @@ function registerLayoutSteps(test) {
|
|
|
904
876
|
const { Given, When, Then } = createBdd12(test);
|
|
905
877
|
Then(
|
|
906
878
|
"I should see the {string} panel",
|
|
907
|
-
{ tags: "@ui or @hybrid" },
|
|
908
879
|
async ({ page, world }, panelName) => {
|
|
909
880
|
const resolvedName = interpolate(panelName, world.vars);
|
|
910
881
|
const panel = page.getByTestId(`${resolvedName}-panel`);
|
|
@@ -913,7 +884,6 @@ function registerLayoutSteps(test) {
|
|
|
913
884
|
);
|
|
914
885
|
Then(
|
|
915
886
|
"I should not see the {string} panel",
|
|
916
|
-
{ tags: "@ui or @hybrid" },
|
|
917
887
|
async ({ page, world }, panelName) => {
|
|
918
888
|
const resolvedName = interpolate(panelName, world.vars);
|
|
919
889
|
const panel = page.getByTestId(`${resolvedName}-panel`);
|
|
@@ -922,7 +892,6 @@ function registerLayoutSteps(test) {
|
|
|
922
892
|
);
|
|
923
893
|
Then(
|
|
924
894
|
"the {string} panel should be {string}",
|
|
925
|
-
{ tags: "@ui or @hybrid" },
|
|
926
895
|
async ({ page, world }, panelName, state) => {
|
|
927
896
|
const resolvedName = interpolate(panelName, world.vars);
|
|
928
897
|
const panel = page.getByTestId(`${resolvedName}-panel`);
|
|
@@ -937,7 +906,6 @@ function registerLayoutSteps(test) {
|
|
|
937
906
|
);
|
|
938
907
|
Then(
|
|
939
908
|
"the {string} panel should be full width",
|
|
940
|
-
{ tags: "@ui or @hybrid" },
|
|
941
909
|
async ({ page, world }, panelName) => {
|
|
942
910
|
const resolvedName = interpolate(panelName, world.vars);
|
|
943
911
|
const panel = page.getByTestId(`${resolvedName}-panel`);
|
|
@@ -949,7 +917,6 @@ function registerLayoutSteps(test) {
|
|
|
949
917
|
);
|
|
950
918
|
Then(
|
|
951
919
|
"the {string} panel should be narrow",
|
|
952
|
-
{ tags: "@ui or @hybrid" },
|
|
953
920
|
async ({ page, world }, panelName) => {
|
|
954
921
|
const resolvedName = interpolate(panelName, world.vars);
|
|
955
922
|
const panel = page.getByTestId(`${resolvedName}-panel`);
|
|
@@ -961,7 +928,6 @@ function registerLayoutSteps(test) {
|
|
|
961
928
|
);
|
|
962
929
|
Then(
|
|
963
930
|
"I should see a split view layout",
|
|
964
|
-
{ tags: "@ui or @hybrid" },
|
|
965
931
|
async ({ page }) => {
|
|
966
932
|
const splitContainer = page.locator("[data-testid='split-view'], .split-view, [data-split-view]");
|
|
967
933
|
await expect5(splitContainer.first()).toBeVisible();
|
|
@@ -969,7 +935,6 @@ function registerLayoutSteps(test) {
|
|
|
969
935
|
);
|
|
970
936
|
Then(
|
|
971
937
|
"I should not see a split view layout",
|
|
972
|
-
{ tags: "@ui or @hybrid" },
|
|
973
938
|
async ({ page }) => {
|
|
974
939
|
const splitContainer = page.locator("[data-testid='split-view'], .split-view, [data-split-view]");
|
|
975
940
|
const count = await splitContainer.count();
|
|
@@ -978,7 +943,6 @@ function registerLayoutSteps(test) {
|
|
|
978
943
|
);
|
|
979
944
|
Then(
|
|
980
945
|
"the sidebar should be visible",
|
|
981
|
-
{ tags: "@ui or @hybrid" },
|
|
982
946
|
async ({ page }) => {
|
|
983
947
|
const sidebar = page.locator("[data-testid='sidebar'], aside, nav.sidebar, .sidebar");
|
|
984
948
|
await expect5(sidebar.first()).toBeVisible();
|
|
@@ -986,7 +950,6 @@ function registerLayoutSteps(test) {
|
|
|
986
950
|
);
|
|
987
951
|
Then(
|
|
988
952
|
"the sidebar should be hidden",
|
|
989
|
-
{ tags: "@ui or @hybrid" },
|
|
990
953
|
async ({ page }) => {
|
|
991
954
|
const sidebar = page.locator("[data-testid='sidebar'], aside.sidebar, nav.sidebar");
|
|
992
955
|
const count = await sidebar.count();
|
|
@@ -997,7 +960,6 @@ function registerLayoutSteps(test) {
|
|
|
997
960
|
);
|
|
998
961
|
Then(
|
|
999
962
|
"the sidebar should be collapsed",
|
|
1000
|
-
{ tags: "@ui or @hybrid" },
|
|
1001
963
|
async ({ page }) => {
|
|
1002
964
|
const sidebar = page.locator("[data-testid='sidebar'], aside, nav.sidebar, .sidebar").first();
|
|
1003
965
|
const isCollapsed = await sidebar.evaluate((el) => {
|
|
@@ -1008,7 +970,6 @@ function registerLayoutSteps(test) {
|
|
|
1008
970
|
);
|
|
1009
971
|
Then(
|
|
1010
972
|
"I should see a modal dialog",
|
|
1011
|
-
{ tags: "@ui or @hybrid" },
|
|
1012
973
|
async ({ page }) => {
|
|
1013
974
|
const modal = page.locator("[role='dialog'], [data-testid='modal'], .modal, [aria-modal='true']");
|
|
1014
975
|
await expect5(modal.first()).toBeVisible();
|
|
@@ -1016,7 +977,6 @@ function registerLayoutSteps(test) {
|
|
|
1016
977
|
);
|
|
1017
978
|
Then(
|
|
1018
979
|
"I should not see a modal dialog",
|
|
1019
|
-
{ tags: "@ui or @hybrid" },
|
|
1020
980
|
async ({ page }) => {
|
|
1021
981
|
const modal = page.locator("[role='dialog'], [data-testid='modal'], .modal, [aria-modal='true']");
|
|
1022
982
|
const count = await modal.count();
|
|
@@ -1027,7 +987,6 @@ function registerLayoutSteps(test) {
|
|
|
1027
987
|
);
|
|
1028
988
|
Then(
|
|
1029
989
|
"I should see the {string} modal",
|
|
1030
|
-
{ tags: "@ui or @hybrid" },
|
|
1031
990
|
async ({ page, world }, modalName) => {
|
|
1032
991
|
const resolvedName = interpolate(modalName, world.vars);
|
|
1033
992
|
const modal = page.getByTestId(`${resolvedName}-modal`);
|
|
@@ -1036,7 +995,6 @@ function registerLayoutSteps(test) {
|
|
|
1036
995
|
);
|
|
1037
996
|
Given(
|
|
1038
997
|
"the viewport is {string} size",
|
|
1039
|
-
{ tags: "@ui or @hybrid" },
|
|
1040
998
|
async ({ page }, sizeName) => {
|
|
1041
999
|
const sizes = {
|
|
1042
1000
|
mobile: { width: 375, height: 667 },
|
|
@@ -1053,14 +1011,12 @@ function registerLayoutSteps(test) {
|
|
|
1053
1011
|
);
|
|
1054
1012
|
Given(
|
|
1055
1013
|
"the viewport is {int}x{int}",
|
|
1056
|
-
{ tags: "@ui or @hybrid" },
|
|
1057
1014
|
async ({ page }, width, height) => {
|
|
1058
1015
|
await page.setViewportSize({ width, height });
|
|
1059
1016
|
}
|
|
1060
1017
|
);
|
|
1061
1018
|
Then(
|
|
1062
1019
|
"the layout should be responsive",
|
|
1063
|
-
{ tags: "@ui or @hybrid" },
|
|
1064
1020
|
async ({ page }) => {
|
|
1065
1021
|
const original = page.viewportSize();
|
|
1066
1022
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
@@ -1074,7 +1030,6 @@ function registerLayoutSteps(test) {
|
|
|
1074
1030
|
);
|
|
1075
1031
|
Then(
|
|
1076
1032
|
"the {string} tab should be active",
|
|
1077
|
-
{ tags: "@ui or @hybrid" },
|
|
1078
1033
|
async ({ page, world }, tabName) => {
|
|
1079
1034
|
const resolvedName = interpolate(tabName, world.vars);
|
|
1080
1035
|
const tab = page.getByRole("tab", { name: resolvedName });
|
|
@@ -1083,7 +1038,6 @@ function registerLayoutSteps(test) {
|
|
|
1083
1038
|
);
|
|
1084
1039
|
Then(
|
|
1085
1040
|
"the {string} tab should not be active",
|
|
1086
|
-
{ tags: "@ui or @hybrid" },
|
|
1087
1041
|
async ({ page, world }, tabName) => {
|
|
1088
1042
|
const resolvedName = interpolate(tabName, world.vars);
|
|
1089
1043
|
const tab = page.getByRole("tab", { name: resolvedName });
|
|
@@ -1092,7 +1046,6 @@ function registerLayoutSteps(test) {
|
|
|
1092
1046
|
);
|
|
1093
1047
|
When(
|
|
1094
1048
|
"I click the {string} tab",
|
|
1095
|
-
{ tags: "@ui or @hybrid" },
|
|
1096
1049
|
async ({ page, world }, tabName) => {
|
|
1097
1050
|
const resolvedName = interpolate(tabName, world.vars);
|
|
1098
1051
|
const tab = page.getByRole("tab", { name: resolvedName });
|
|
@@ -1174,7 +1127,6 @@ function registerUiAuthSteps(test) {
|
|
|
1174
1127
|
const { Given } = createBdd13(test);
|
|
1175
1128
|
Given(
|
|
1176
1129
|
"I am authenticated in UI as {string}",
|
|
1177
|
-
{ tags: "@ui" },
|
|
1178
1130
|
async ({ page, world }, rolesStr) => {
|
|
1179
1131
|
const roles = rolesStr.split(",").map((r) => r.trim());
|
|
1180
1132
|
const testRunId = world.testRunId || world.vars.test_run_id || Date.now();
|
|
@@ -1192,7 +1144,6 @@ function registerUiAuthSteps(test) {
|
|
|
1192
1144
|
);
|
|
1193
1145
|
Given(
|
|
1194
1146
|
"I am authenticated in UI as {string} for tenant {string}",
|
|
1195
|
-
{ tags: "@ui" },
|
|
1196
1147
|
async ({ page, world }, rolesStr, tenantId) => {
|
|
1197
1148
|
const roles = rolesStr.split(",").map((r) => r.trim());
|
|
1198
1149
|
const testRunId = world.testRunId || world.vars.test_run_id || Date.now();
|
|
@@ -1207,7 +1158,6 @@ function registerUiAuthSteps(test) {
|
|
|
1207
1158
|
);
|
|
1208
1159
|
Given(
|
|
1209
1160
|
"I am authenticated in UI as {string} with id {string}",
|
|
1210
|
-
{ tags: "@ui" },
|
|
1211
1161
|
async ({ page, world }, rolesStr, userId) => {
|
|
1212
1162
|
const roles = rolesStr.split(",").map((r) => r.trim());
|
|
1213
1163
|
const resolvedUserId = interpolate(userId, world.vars);
|
|
@@ -1221,7 +1171,6 @@ function registerUiAuthSteps(test) {
|
|
|
1221
1171
|
);
|
|
1222
1172
|
Given(
|
|
1223
1173
|
"I am authenticated in UI with bearer token {string}",
|
|
1224
|
-
{ tags: "@ui" },
|
|
1225
1174
|
async ({ page, world }, token) => {
|
|
1226
1175
|
const resolvedToken = interpolate(token, world.vars);
|
|
1227
1176
|
await setupBearerAuth(page, resolvedToken);
|
|
@@ -1230,7 +1179,6 @@ function registerUiAuthSteps(test) {
|
|
|
1230
1179
|
);
|
|
1231
1180
|
Given(
|
|
1232
1181
|
"I am authenticated in UI with headers:",
|
|
1233
|
-
{ tags: "@ui" },
|
|
1234
1182
|
async ({ page, world }, dataTable) => {
|
|
1235
1183
|
const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
|
|
1236
1184
|
header: row[0],
|
|
@@ -1254,7 +1202,6 @@ function registerUiAuthSteps(test) {
|
|
|
1254
1202
|
);
|
|
1255
1203
|
Given(
|
|
1256
1204
|
"I switch UI user to {string} with id {string}",
|
|
1257
|
-
{ tags: "@ui" },
|
|
1258
1205
|
async ({ page, world }, rolesStr, userId) => {
|
|
1259
1206
|
const roles = rolesStr.split(",").map((r) => r.trim());
|
|
1260
1207
|
const resolvedUserId = interpolate(userId, world.vars);
|
|
@@ -1272,121 +1219,115 @@ function registerUiAuthSteps(test) {
|
|
|
1272
1219
|
import { createBdd as createBdd14 } from "playwright-bdd";
|
|
1273
1220
|
function registerTuiBasicSteps(test) {
|
|
1274
1221
|
const { Given, When, Then } = createBdd14(test);
|
|
1275
|
-
Given("I start the TUI application",
|
|
1222
|
+
Given("I start the TUI application", async ({ tui }) => {
|
|
1276
1223
|
await tui.start();
|
|
1277
1224
|
await tui.waitForReady();
|
|
1278
1225
|
});
|
|
1279
|
-
Given("the TUI application is running",
|
|
1226
|
+
Given("the TUI application is running", async ({ tui }) => {
|
|
1280
1227
|
if (!tui.isRunning()) {
|
|
1281
1228
|
await tui.start();
|
|
1282
1229
|
await tui.waitForReady();
|
|
1283
1230
|
}
|
|
1284
1231
|
});
|
|
1285
|
-
When("I restart the TUI application",
|
|
1232
|
+
When("I restart the TUI application", async ({ tui }) => {
|
|
1286
1233
|
await tui.restart();
|
|
1287
1234
|
await tui.waitForReady();
|
|
1288
1235
|
});
|
|
1289
|
-
When("I stop the TUI application",
|
|
1236
|
+
When("I stop the TUI application", async ({ tui }) => {
|
|
1290
1237
|
await tui.stop();
|
|
1291
1238
|
});
|
|
1292
|
-
When("I type {string}",
|
|
1239
|
+
When("I type {string}", async ({ tui, world }, text) => {
|
|
1293
1240
|
await tui.typeText(interpolate(text, world.vars));
|
|
1294
1241
|
});
|
|
1295
|
-
When("I type {string} slowly",
|
|
1242
|
+
When("I type {string} slowly", async ({ tui, world }, text) => {
|
|
1296
1243
|
await tui.typeText(interpolate(text, world.vars), { delay: 50 });
|
|
1297
1244
|
});
|
|
1298
|
-
When("I press {string}",
|
|
1245
|
+
When("I press {string}", async ({ tui }, key) => {
|
|
1299
1246
|
await tui.pressKey(key);
|
|
1300
1247
|
});
|
|
1301
|
-
When("I press {string} with ctrl",
|
|
1248
|
+
When("I press {string} with ctrl", async ({ tui }, key) => {
|
|
1302
1249
|
await tui.pressKey(key, { ctrl: true });
|
|
1303
1250
|
});
|
|
1304
|
-
When("I press {string} with alt",
|
|
1251
|
+
When("I press {string} with alt", async ({ tui }, key) => {
|
|
1305
1252
|
await tui.pressKey(key, { alt: true });
|
|
1306
1253
|
});
|
|
1307
|
-
When("I press {string} with shift",
|
|
1254
|
+
When("I press {string} with shift", async ({ tui }, key) => {
|
|
1308
1255
|
await tui.pressKey(key, { shift: true });
|
|
1309
1256
|
});
|
|
1310
|
-
When("I press enter",
|
|
1257
|
+
When("I press enter", async ({ tui }) => {
|
|
1311
1258
|
await tui.pressKey("enter");
|
|
1312
1259
|
});
|
|
1313
|
-
When("I press tab",
|
|
1260
|
+
When("I press tab", async ({ tui }) => {
|
|
1314
1261
|
await tui.pressKey("tab");
|
|
1315
1262
|
});
|
|
1316
|
-
When("I press escape",
|
|
1263
|
+
When("I press escape", async ({ tui }) => {
|
|
1317
1264
|
await tui.pressKey("escape");
|
|
1318
1265
|
});
|
|
1319
1266
|
When(
|
|
1320
1267
|
"I fill the TUI field {string} with {string}",
|
|
1321
|
-
{ tags: "@tui" },
|
|
1322
1268
|
async ({ tui, world }, field, value) => {
|
|
1323
1269
|
await tui.fillField(interpolate(field, world.vars), interpolate(value, world.vars));
|
|
1324
1270
|
}
|
|
1325
1271
|
);
|
|
1326
1272
|
When(
|
|
1327
1273
|
"I enter {string} in the {string} field",
|
|
1328
|
-
{ tags: "@tui" },
|
|
1329
1274
|
async ({ tui, world }, value, field) => {
|
|
1330
1275
|
await tui.fillField(interpolate(field, world.vars), interpolate(value, world.vars));
|
|
1331
1276
|
}
|
|
1332
1277
|
);
|
|
1333
|
-
When("I select {string}",
|
|
1278
|
+
When("I select {string}", async ({ tui, world }, option) => {
|
|
1334
1279
|
await tui.selectOption(interpolate(option, world.vars));
|
|
1335
1280
|
});
|
|
1336
|
-
When("I select option {string}",
|
|
1281
|
+
When("I select option {string}", async ({ tui, world }, option) => {
|
|
1337
1282
|
await tui.selectOption(interpolate(option, world.vars));
|
|
1338
1283
|
});
|
|
1339
|
-
When("I click at position {int}, {int}",
|
|
1284
|
+
When("I click at position {int}, {int}", async ({ tui }, x, y) => {
|
|
1340
1285
|
await tui.click(x, y);
|
|
1341
1286
|
});
|
|
1342
|
-
When("I click on {string}",
|
|
1287
|
+
When("I click on {string}", async ({ tui, world }, text) => {
|
|
1343
1288
|
await tui.clickOnText(interpolate(text, world.vars));
|
|
1344
1289
|
});
|
|
1345
|
-
Then("I should see {string}",
|
|
1290
|
+
Then("I should see {string}", async ({ tui, world }, text) => {
|
|
1346
1291
|
await tui.expectText(interpolate(text, world.vars));
|
|
1347
1292
|
});
|
|
1348
|
-
Then("I should see {string} in the terminal",
|
|
1293
|
+
Then("I should see {string} in the terminal", async ({ tui, world }, text) => {
|
|
1349
1294
|
await tui.expectText(interpolate(text, world.vars));
|
|
1350
1295
|
});
|
|
1351
|
-
Then("I should see
|
|
1352
|
-
await tui.expectText(interpolate(text, world.vars));
|
|
1353
|
-
});
|
|
1354
|
-
Then("I should not see {string}", { tags: "@tui" }, async ({ tui, world }, text) => {
|
|
1296
|
+
Then("I should not see {string}", async ({ tui, world }, text) => {
|
|
1355
1297
|
await tui.expectNotText(interpolate(text, world.vars));
|
|
1356
1298
|
});
|
|
1357
|
-
Then("the screen should contain {string}",
|
|
1299
|
+
Then("the screen should contain {string}", async ({ tui, world }, text) => {
|
|
1358
1300
|
await tui.assertScreenContains(interpolate(text, world.vars));
|
|
1359
1301
|
});
|
|
1360
|
-
Then("the screen should match pattern {string}",
|
|
1302
|
+
Then("the screen should match pattern {string}", async ({ tui }, pattern) => {
|
|
1361
1303
|
await tui.assertScreenMatches(new RegExp(pattern));
|
|
1362
1304
|
});
|
|
1363
|
-
When("I wait for {string}",
|
|
1305
|
+
When("I wait for {string}", async ({ tui, world }, text) => {
|
|
1364
1306
|
await tui.waitForText(interpolate(text, world.vars));
|
|
1365
1307
|
});
|
|
1366
1308
|
When(
|
|
1367
1309
|
"I wait for {string} for {int} seconds",
|
|
1368
|
-
{ tags: "@tui" },
|
|
1369
1310
|
async ({ tui, world }, text, seconds) => {
|
|
1370
1311
|
await tui.waitForText(interpolate(text, world.vars), { timeout: seconds * 1e3 });
|
|
1371
1312
|
}
|
|
1372
1313
|
);
|
|
1373
|
-
When("I wait {int} seconds",
|
|
1314
|
+
When("I wait {int} seconds", async ({ tui }, seconds) => {
|
|
1374
1315
|
await tui.waitSeconds(seconds);
|
|
1375
1316
|
});
|
|
1376
|
-
Then("the screen should match snapshot {string}",
|
|
1317
|
+
Then("the screen should match snapshot {string}", async ({ tui }, name) => {
|
|
1377
1318
|
const result = await tui.matchSnapshot(name);
|
|
1378
1319
|
if (!result.pass) {
|
|
1379
1320
|
throw new Error(`Snapshot "${name}" mismatch:
|
|
1380
1321
|
${result.diff || "No diff available"}`);
|
|
1381
1322
|
}
|
|
1382
1323
|
});
|
|
1383
|
-
Then("I take a snapshot named {string}",
|
|
1324
|
+
Then("I take a snapshot named {string}", async ({ tui }, name) => {
|
|
1384
1325
|
await tui.takeSnapshot(name);
|
|
1385
1326
|
});
|
|
1386
|
-
When("I clear the terminal",
|
|
1327
|
+
When("I clear the terminal", async ({ tui }) => {
|
|
1387
1328
|
await tui.clear();
|
|
1388
1329
|
});
|
|
1389
|
-
When("I resize the terminal to {int}x{int}",
|
|
1330
|
+
When("I resize the terminal to {int}x{int}", async ({ tui }, cols, rows) => {
|
|
1390
1331
|
await tui.resize({ cols, rows });
|
|
1391
1332
|
});
|
|
1392
1333
|
}
|
|
@@ -1395,25 +1336,25 @@ ${result.diff || "No diff available"}`);
|
|
|
1395
1336
|
import { createBdd as createBdd15 } from "playwright-bdd";
|
|
1396
1337
|
function registerTuiWizardSteps(test) {
|
|
1397
1338
|
const { Given, When, Then } = createBdd15(test);
|
|
1398
|
-
When("I navigate down {int} times",
|
|
1339
|
+
When("I navigate down {int} times", async ({ tui }, times) => {
|
|
1399
1340
|
for (let i = 0; i < times; i++) {
|
|
1400
1341
|
await tui.pressKey("down");
|
|
1401
1342
|
}
|
|
1402
1343
|
});
|
|
1403
|
-
When("I navigate up {int} times",
|
|
1344
|
+
When("I navigate up {int} times", async ({ tui }, times) => {
|
|
1404
1345
|
for (let i = 0; i < times; i++) {
|
|
1405
1346
|
await tui.pressKey("up");
|
|
1406
1347
|
}
|
|
1407
1348
|
});
|
|
1408
|
-
When("I navigate to {string} and select",
|
|
1349
|
+
When("I navigate to {string} and select", async ({ tui, world }, option) => {
|
|
1409
1350
|
const target = interpolate(option, world.vars);
|
|
1410
1351
|
await tui.waitForText(target);
|
|
1411
1352
|
await tui.pressKey("enter");
|
|
1412
1353
|
});
|
|
1413
|
-
When("I go back",
|
|
1354
|
+
When("I go back", async ({ tui }) => {
|
|
1414
1355
|
await tui.pressKey("escape");
|
|
1415
1356
|
});
|
|
1416
|
-
When("I fill the form:",
|
|
1357
|
+
When("I fill the TUI form:", async ({ tui, world }, dataTable) => {
|
|
1417
1358
|
const rows = dataTable.hashes();
|
|
1418
1359
|
for (const row of rows) {
|
|
1419
1360
|
const field = interpolate(row.field || row.Field, world.vars);
|
|
@@ -1422,21 +1363,21 @@ function registerTuiWizardSteps(test) {
|
|
|
1422
1363
|
await tui.pressKey("tab");
|
|
1423
1364
|
}
|
|
1424
1365
|
});
|
|
1425
|
-
When("I submit the form",
|
|
1366
|
+
When("I submit the form", async ({ tui }) => {
|
|
1426
1367
|
await tui.pressKey("enter");
|
|
1427
1368
|
});
|
|
1428
|
-
When("I submit the form with ctrl+s",
|
|
1369
|
+
When("I submit the form with ctrl+s", async ({ tui }) => {
|
|
1429
1370
|
await tui.pressKey("s", { ctrl: true });
|
|
1430
1371
|
});
|
|
1431
|
-
When("I select menu item {string}",
|
|
1372
|
+
When("I select menu item {string}", async ({ tui, world }, item) => {
|
|
1432
1373
|
const target = interpolate(item, world.vars);
|
|
1433
1374
|
await tui.waitForText(target);
|
|
1434
1375
|
await tui.selectOption(target);
|
|
1435
1376
|
});
|
|
1436
|
-
When("I open the menu",
|
|
1377
|
+
When("I open the menu", async ({ tui }) => {
|
|
1437
1378
|
await tui.pressKey("m", { alt: true });
|
|
1438
1379
|
});
|
|
1439
|
-
When("I select from dropdown {string} value {string}",
|
|
1380
|
+
When("I select from dropdown {string} value {string}", async ({ tui, world }, dropdown, value) => {
|
|
1440
1381
|
const dropdownLabel = interpolate(dropdown, world.vars);
|
|
1441
1382
|
const selectedValue = interpolate(value, world.vars);
|
|
1442
1383
|
await tui.waitForText(dropdownLabel);
|
|
@@ -1444,25 +1385,25 @@ function registerTuiWizardSteps(test) {
|
|
|
1444
1385
|
await tui.waitForText(selectedValue);
|
|
1445
1386
|
await tui.pressKey("enter");
|
|
1446
1387
|
});
|
|
1447
|
-
When(
|
|
1388
|
+
When(/^I press ctrl\+([^+\s]+)$/, async ({ tui }, key) => {
|
|
1448
1389
|
await tui.pressKey(key, { ctrl: true });
|
|
1449
1390
|
});
|
|
1450
|
-
When("I press alt+{word}",
|
|
1391
|
+
When("I press alt+{word}", async ({ tui }, key) => {
|
|
1451
1392
|
await tui.pressKey(key, { alt: true });
|
|
1452
1393
|
});
|
|
1453
|
-
When("I press shift+{word}",
|
|
1394
|
+
When("I press shift+{word}", async ({ tui }, key) => {
|
|
1454
1395
|
await tui.pressKey(key, { shift: true });
|
|
1455
1396
|
});
|
|
1456
|
-
When("I press ctrl+shift+{word}",
|
|
1397
|
+
When("I press ctrl+shift+{word}", async ({ tui }, key) => {
|
|
1457
1398
|
await tui.pressKey(key, { ctrl: true, shift: true });
|
|
1458
1399
|
});
|
|
1459
|
-
When("I quit the application",
|
|
1400
|
+
When("I quit the application", async ({ tui }) => {
|
|
1460
1401
|
await tui.pressKey("q");
|
|
1461
1402
|
});
|
|
1462
|
-
When("I force quit the application",
|
|
1403
|
+
When("I force quit the application", async ({ tui }) => {
|
|
1463
1404
|
await tui.pressKey("c", { ctrl: true });
|
|
1464
1405
|
});
|
|
1465
|
-
Then("line {int} should contain {string}",
|
|
1406
|
+
Then("line {int} should contain {string}", async ({ tui, world }, lineNum, text) => {
|
|
1466
1407
|
const lines = await tui.getScreenLines();
|
|
1467
1408
|
const expectedText = interpolate(text, world.vars);
|
|
1468
1409
|
const lineIndex = lineNum - 1;
|
|
@@ -1474,7 +1415,7 @@ function registerTuiWizardSteps(test) {
|
|
|
1474
1415
|
Actual: "${lines[lineIndex]}"`);
|
|
1475
1416
|
}
|
|
1476
1417
|
});
|
|
1477
|
-
Then("the first line should contain {string}",
|
|
1418
|
+
Then("the first line should contain {string}", async ({ tui, world }, text) => {
|
|
1478
1419
|
const lines = await tui.getScreenLines();
|
|
1479
1420
|
const expectedText = interpolate(text, world.vars);
|
|
1480
1421
|
if (!lines[0]?.includes(expectedText)) {
|
|
@@ -1482,7 +1423,7 @@ Actual: "${lines[lineIndex]}"`);
|
|
|
1482
1423
|
Actual: "${lines[0]}"`);
|
|
1483
1424
|
}
|
|
1484
1425
|
});
|
|
1485
|
-
Then("the last line should contain {string}",
|
|
1426
|
+
Then("the last line should contain {string}", async ({ tui, world }, text) => {
|
|
1486
1427
|
const lines = await tui.getScreenLines();
|
|
1487
1428
|
const expectedText = interpolate(text, world.vars);
|
|
1488
1429
|
const lastLine = lines[lines.length - 1] || "";
|
|
@@ -1491,49 +1432,49 @@ Actual: "${lines[0]}"`);
|
|
|
1491
1432
|
Actual: "${lastLine}"`);
|
|
1492
1433
|
}
|
|
1493
1434
|
});
|
|
1494
|
-
Then("I should see all of:",
|
|
1435
|
+
Then("I should see all of:", async ({ tui, world }, dataTable) => {
|
|
1495
1436
|
const rows = dataTable.raw();
|
|
1496
1437
|
for (const row of rows) {
|
|
1497
1438
|
const text = interpolate(row[0], world.vars);
|
|
1498
1439
|
await tui.expectText(text);
|
|
1499
1440
|
}
|
|
1500
1441
|
});
|
|
1501
|
-
Then("I should not see any of:",
|
|
1442
|
+
Then("I should not see any of:", async ({ tui, world }, dataTable) => {
|
|
1502
1443
|
const rows = dataTable.raw();
|
|
1503
1444
|
for (const row of rows) {
|
|
1504
1445
|
const text = interpolate(row[0], world.vars);
|
|
1505
1446
|
await tui.expectNotText(text);
|
|
1506
1447
|
}
|
|
1507
1448
|
});
|
|
1508
|
-
When("I capture the screen",
|
|
1449
|
+
When("I capture the screen", async ({ tui, world }) => {
|
|
1509
1450
|
const capture = await tui.captureScreen();
|
|
1510
1451
|
world.vars["lastScreenCapture"] = capture.text;
|
|
1511
1452
|
});
|
|
1512
|
-
Then("I print the screen",
|
|
1453
|
+
Then("I print the screen", async ({ tui }) => {
|
|
1513
1454
|
const text = await tui.getScreenText();
|
|
1514
1455
|
console.log("=== Screen Content ===");
|
|
1515
1456
|
console.log(text);
|
|
1516
1457
|
console.log("======================");
|
|
1517
1458
|
});
|
|
1518
|
-
When("I execute command {string}",
|
|
1459
|
+
When("I execute command {string}", async ({ tui, world }, command) => {
|
|
1519
1460
|
const cmd = interpolate(command, world.vars);
|
|
1520
1461
|
await tui.typeText(cmd);
|
|
1521
1462
|
await tui.pressKey("enter");
|
|
1522
1463
|
});
|
|
1523
|
-
When("I run {string}",
|
|
1464
|
+
When("I run {string}", async ({ tui, world }, command) => {
|
|
1524
1465
|
const cmd = interpolate(command, world.vars);
|
|
1525
1466
|
await tui.typeText(cmd);
|
|
1526
1467
|
await tui.pressKey("enter");
|
|
1527
1468
|
});
|
|
1528
|
-
When("I confirm the dialog",
|
|
1469
|
+
When("I confirm the dialog", async ({ tui }) => {
|
|
1529
1470
|
await tui.typeText("y");
|
|
1530
1471
|
await tui.pressKey("enter");
|
|
1531
1472
|
});
|
|
1532
|
-
When("I cancel the dialog",
|
|
1473
|
+
When("I cancel the dialog", async ({ tui }) => {
|
|
1533
1474
|
await tui.typeText("n");
|
|
1534
1475
|
await tui.pressKey("enter");
|
|
1535
1476
|
});
|
|
1536
|
-
When("I dismiss the dialog",
|
|
1477
|
+
When("I dismiss the dialog", async ({ tui }) => {
|
|
1537
1478
|
await tui.pressKey("escape");
|
|
1538
1479
|
});
|
|
1539
1480
|
}
|