@esimplicity/stack-tests 0.1.4 → 0.1.6

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 CHANGED
@@ -1,4 +1,4 @@
1
- # @kata/stack-tests
1
+ # @esimplicity/stack-tests
2
2
 
3
3
  Reusable Playwright-BDD fixtures, ports, adapters, and step registrations for API, UI, and hybrid testing. Designed to be consumed as a dev dependency across repos.
4
4
 
@@ -9,13 +9,13 @@ GitHub Packages (recommended for release builds):
9
9
  ```bash
10
10
  npm config set @kata:registry https://npm.pkg.github.com
11
11
  npm set //npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
12
- npm install -D @kata/stack-tests @playwright/test playwright-bdd
12
+ npm install -D @esimplicity/stack-tests @playwright/test playwright-bdd
13
13
  ```
14
14
 
15
15
  Workspace/local development (from this monorepo):
16
16
 
17
17
  ```bash
18
- bun add -d @kata/stack-tests@"file:../packages/stack-tests" @playwright/test playwright-bdd
18
+ bun add -d @esimplicity/stack-tests@"file:../packages/stack-tests" @playwright/test playwright-bdd
19
19
  ```
20
20
 
21
21
  ## What’s included
@@ -37,7 +37,7 @@ import {
37
37
  PlaywrightUiAdapter,
38
38
  UniversalAuthAdapter,
39
39
  DefaultCleanupAdapter,
40
- } from '@kata/stack-tests';
40
+ } from '@esimplicity/stack-tests';
41
41
 
42
42
  export const test = createBddTest({
43
43
  createApi: ({ apiRequest }) => new PlaywrightApiAdapter(apiRequest),
@@ -51,7 +51,7 @@ export const test = createBddTest({
51
51
  ```ts
52
52
  // features/steps/steps_api/index.ts
53
53
  import { test } from '../fixtures';
54
- import { registerApiSteps } from '@kata/stack-tests/steps';
54
+ import { registerApiSteps } from '@esimplicity/stack-tests/steps';
55
55
  registerApiSteps(test);
56
56
  ```
57
57
 
@@ -206,10 +206,106 @@ function registerSharedVarSteps(test) {
206
206
  });
207
207
  }
208
208
 
209
- // src/steps/ui.basic.ts
209
+ // src/steps/shared.flags.ts
210
210
  import { createBdd as createBdd7 } from "playwright-bdd";
211
+ var globalFlags = {};
212
+ function isFlagEnabled(world, flagName) {
213
+ const worldFlags = world._featureFlags || {};
214
+ if (flagName in worldFlags) {
215
+ return worldFlags[flagName];
216
+ }
217
+ return globalFlags[flagName] ?? false;
218
+ }
219
+ function setFlag(world, flagName, enabled) {
220
+ if (!world._featureFlags) {
221
+ world._featureFlags = {};
222
+ }
223
+ world._featureFlags[flagName] = enabled;
224
+ world.vars[`flag_${flagName}`] = String(enabled);
225
+ }
226
+ function registerFlagSteps(test) {
227
+ const { Given, Then } = createBdd7(test);
228
+ Given(
229
+ "the feature flag {string} is enabled",
230
+ async ({ world }, flagName) => {
231
+ setFlag(world, flagName, true);
232
+ console.log(`[BDD] Feature flag "${flagName}" enabled`);
233
+ }
234
+ );
235
+ Given(
236
+ "the feature flag {string} is disabled",
237
+ async ({ world }, flagName) => {
238
+ setFlag(world, flagName, false);
239
+ console.log(`[BDD] Feature flag "${flagName}" disabled`);
240
+ }
241
+ );
242
+ Given(
243
+ "the feature flag {string} is set to {string}",
244
+ async ({ world }, flagName, value) => {
245
+ const enabled = value.toLowerCase() === "true" || value === "1";
246
+ setFlag(world, flagName, enabled);
247
+ console.log(`[BDD] Feature flag "${flagName}" set to ${enabled}`);
248
+ }
249
+ );
250
+ Given(
251
+ "the following feature flags are enabled:",
252
+ async ({ world }, dataTable) => {
253
+ const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1) || [];
254
+ for (const row of rows) {
255
+ const flagName = row.flag || row[0];
256
+ setFlag(world, flagName, true);
257
+ console.log(`[BDD] Feature flag "${flagName}" enabled`);
258
+ }
259
+ }
260
+ );
261
+ Given(
262
+ "the following feature flags are disabled:",
263
+ async ({ world }, dataTable) => {
264
+ const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1) || [];
265
+ for (const row of rows) {
266
+ const flagName = row.flag || row[0];
267
+ setFlag(world, flagName, false);
268
+ console.log(`[BDD] Feature flag "${flagName}" disabled`);
269
+ }
270
+ }
271
+ );
272
+ Then(
273
+ "the feature flag {string} should be enabled",
274
+ async ({ world }, flagName) => {
275
+ const enabled = isFlagEnabled(world, flagName);
276
+ if (!enabled) {
277
+ throw new Error(`Expected feature flag "${flagName}" to be enabled, but it was disabled`);
278
+ }
279
+ }
280
+ );
281
+ Then(
282
+ "the feature flag {string} should be disabled",
283
+ async ({ world }, flagName) => {
284
+ const enabled = isFlagEnabled(world, flagName);
285
+ if (enabled) {
286
+ throw new Error(`Expected feature flag "${flagName}" to be disabled, but it was enabled`);
287
+ }
288
+ }
289
+ );
290
+ Then(
291
+ "I log all feature flags",
292
+ async ({ world }) => {
293
+ const worldFlags = world._featureFlags || {};
294
+ console.log("[DEBUG] Feature flags:");
295
+ for (const [name, enabled] of Object.entries(worldFlags)) {
296
+ console.log(` - ${name}: ${enabled ? "enabled" : "disabled"}`);
297
+ }
298
+ if (Object.keys(worldFlags).length === 0) {
299
+ console.log(" (no flags set)");
300
+ }
301
+ }
302
+ );
303
+ }
304
+
305
+ // src/steps/ui.basic.ts
306
+ import { createBdd as createBdd8 } from "playwright-bdd";
211
307
  function registerUiBasicSteps(test) {
212
- const { Given, When, Then } = createBdd7(test);
308
+ const { Given, When, Then } = createBdd8(test);
213
309
  Given("I navigate to {string}", { tags: "@ui or @hybrid" }, async ({ ui, world }, path) => {
214
310
  await ui.goto(interpolate(path, world.vars));
215
311
  });
@@ -240,7 +336,7 @@ function registerUiBasicSteps(test) {
240
336
  }
241
337
 
242
338
  // src/steps/ui.wizard.ts
243
- import { createBdd as createBdd8 } from "playwright-bdd";
339
+ import { createBdd as createBdd9 } from "playwright-bdd";
244
340
  function resolveValue(input, world) {
245
341
  const interpolated = interpolate(input, world.vars);
246
342
  if (interpolated === input && world.vars[input] !== void 0) {
@@ -338,7 +434,7 @@ function parseRegex(input) {
338
434
  return new RegExp(raw);
339
435
  }
340
436
  function registerWizardSteps(test) {
341
- const { Given, When, Then } = createBdd8(test);
437
+ const { Given, When, Then } = createBdd9(test);
342
438
  Given("I open {string} page", { tags: "@ui or @hybrid" }, async ({ ui, world }, urlOrVar) => {
343
439
  await ui.goto(resolveValue(urlOrVar, world));
344
440
  });
@@ -510,10 +606,596 @@ function registerWizardSteps(test) {
510
606
  );
511
607
  }
512
608
 
609
+ // src/steps/ui.form.ts
610
+ import { createBdd as createBdd10 } from "playwright-bdd";
611
+ function registerFormSteps(test) {
612
+ const { Given, When } = createBdd10(test);
613
+ When(
614
+ "I fill the form:",
615
+ { tags: "@ui or @hybrid" },
616
+ async ({ ui, world }, dataTable) => {
617
+ const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
618
+ field: row[0],
619
+ value: row[1]
620
+ })) || [];
621
+ for (const row of rows) {
622
+ const field = interpolate(row.field, world.vars);
623
+ const value = interpolate(row.value, world.vars);
624
+ await ui.fillLabel(field, value);
625
+ }
626
+ }
627
+ );
628
+ When(
629
+ "I fill the form with {string} locators:",
630
+ { tags: "@ui or @hybrid" },
631
+ async ({ ui, world }, locatorMethod, dataTable) => {
632
+ const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
633
+ field: row[0],
634
+ value: row[1]
635
+ })) || [];
636
+ for (const row of rows) {
637
+ const field = interpolate(row.field, world.vars);
638
+ const value = interpolate(row.value, world.vars);
639
+ await ui.inputInElement("fill", value, "1", field, locatorMethod);
640
+ }
641
+ }
642
+ );
643
+ When(
644
+ "I fill and submit the form:",
645
+ { tags: "@ui or @hybrid" },
646
+ async ({ ui, world }, dataTable) => {
647
+ const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
648
+ field: row[0],
649
+ value: row[1]
650
+ })) || [];
651
+ for (const row of rows) {
652
+ const field = interpolate(row.field, world.vars);
653
+ const value = interpolate(row.value, world.vars);
654
+ await ui.fillLabel(field, value);
655
+ }
656
+ await ui.pressKey("Enter");
657
+ }
658
+ );
659
+ Given(
660
+ "I clear and fill the form:",
661
+ { tags: "@ui or @hybrid" },
662
+ async ({ page, world }, dataTable) => {
663
+ const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
664
+ field: row[0],
665
+ value: row[1]
666
+ })) || [];
667
+ for (const row of rows) {
668
+ const field = interpolate(row.field, world.vars);
669
+ const value = interpolate(row.value, world.vars);
670
+ const locator = page.getByLabel(field);
671
+ await locator.clear();
672
+ await locator.fill(value);
673
+ }
674
+ }
675
+ );
676
+ }
677
+
678
+ // src/steps/ui.debug.ts
679
+ import { createBdd as createBdd11 } from "playwright-bdd";
680
+ function registerDebugSteps(test) {
681
+ const { When, Then } = createBdd11(test);
682
+ When(
683
+ "I capture the page HTML as {string}",
684
+ { tags: "@ui or @hybrid" },
685
+ async ({ page, world }, varName) => {
686
+ const content = await page.content();
687
+ world.vars[varName] = content;
688
+ }
689
+ );
690
+ Then(
691
+ "I log the current URL",
692
+ { tags: "@ui or @hybrid" },
693
+ async ({ page }) => {
694
+ console.log(`[DEBUG] Current URL: ${page.url()}`);
695
+ }
696
+ );
697
+ Then(
698
+ "I log the page title",
699
+ { tags: "@ui or @hybrid" },
700
+ async ({ page }) => {
701
+ const title = await page.title();
702
+ console.log(`[DEBUG] Page title: ${title}`);
703
+ }
704
+ );
705
+ When(
706
+ "I save a screenshot as {string}",
707
+ { tags: "@ui or @hybrid" },
708
+ async ({ page, world }, filename) => {
709
+ const resolvedFilename = interpolate(filename, world.vars);
710
+ await page.screenshot({ path: resolvedFilename });
711
+ console.log(`[DEBUG] Screenshot saved: ${resolvedFilename}`);
712
+ }
713
+ );
714
+ When(
715
+ "I save a full page screenshot as {string}",
716
+ { tags: "@ui or @hybrid" },
717
+ async ({ page, world }, filename) => {
718
+ const resolvedFilename = interpolate(filename, world.vars);
719
+ await page.screenshot({ path: resolvedFilename, fullPage: true });
720
+ console.log(`[DEBUG] Full page screenshot saved: ${resolvedFilename}`);
721
+ }
722
+ );
723
+ When(
724
+ "I pause for debugging",
725
+ { tags: "@ui or @hybrid" },
726
+ async ({ page }) => {
727
+ console.log('[DEBUG] Pausing for debugging. Press "Resume" in Playwright Inspector to continue.');
728
+ await page.pause();
729
+ }
730
+ );
731
+ Then(
732
+ "I print visible text",
733
+ { tags: "@ui or @hybrid" },
734
+ async ({ page }) => {
735
+ const text = await page.innerText("body");
736
+ const truncated = text.length > 2e3 ? `${text.substring(0, 2e3)}...(truncated)` : text;
737
+ console.log(`[DEBUG] Visible text:
738
+ ${truncated}`);
739
+ }
740
+ );
741
+ Then(
742
+ "I count elements matching {string}",
743
+ { tags: "@ui or @hybrid" },
744
+ async ({ page, world }, selector) => {
745
+ const resolvedSelector = interpolate(selector, world.vars);
746
+ const count = await page.locator(resolvedSelector).count();
747
+ console.log(`[DEBUG] Found ${count} elements matching "${resolvedSelector}"`);
748
+ }
749
+ );
750
+ Then(
751
+ "I print browser console messages",
752
+ { tags: "@ui or @hybrid" },
753
+ async ({ page }) => {
754
+ console.log("[DEBUG] Browser console messages will be captured from this point.");
755
+ page.on("console", (msg) => {
756
+ console.log(`[BROWSER ${msg.type().toUpperCase()}] ${msg.text()}`);
757
+ });
758
+ }
759
+ );
760
+ When(
761
+ "I capture viewport size",
762
+ { tags: "@ui or @hybrid" },
763
+ async ({ page, world }) => {
764
+ const viewport = page.viewportSize();
765
+ if (viewport) {
766
+ world.vars.viewportWidth = String(viewport.width);
767
+ world.vars.viewportHeight = String(viewport.height);
768
+ console.log(`[DEBUG] Viewport size: ${viewport.width}x${viewport.height}`);
769
+ } else {
770
+ console.log("[DEBUG] Viewport size not available");
771
+ }
772
+ }
773
+ );
774
+ Then(
775
+ "I log all cookies",
776
+ { tags: "@ui or @hybrid" },
777
+ async ({ page }) => {
778
+ const context = page.context();
779
+ const cookies = await context.cookies();
780
+ console.log(`[DEBUG] Cookies (${cookies.length}):`);
781
+ for (const cookie of cookies) {
782
+ console.log(` - ${cookie.name}: ${cookie.value.substring(0, 50)}${cookie.value.length > 50 ? "..." : ""}`);
783
+ }
784
+ }
785
+ );
786
+ Then(
787
+ "I log localStorage",
788
+ { tags: "@ui or @hybrid" },
789
+ async ({ page }) => {
790
+ const storage = await page.evaluate(() => {
791
+ const items = {};
792
+ for (let i = 0; i < localStorage.length; i++) {
793
+ const key = localStorage.key(i);
794
+ if (key) {
795
+ items[key] = localStorage.getItem(key) || "";
796
+ }
797
+ }
798
+ return items;
799
+ });
800
+ console.log("[DEBUG] localStorage:");
801
+ for (const [key, value] of Object.entries(storage)) {
802
+ const truncated = value.length > 100 ? `${value.substring(0, 100)}...` : value;
803
+ console.log(` - ${key}: ${truncated}`);
804
+ }
805
+ }
806
+ );
807
+ When(
808
+ "I highlight element {string}",
809
+ { tags: "@ui or @hybrid" },
810
+ async ({ page, world }, selector) => {
811
+ const resolvedSelector = interpolate(selector, world.vars);
812
+ await page.evaluate((sel) => {
813
+ const elements = document.querySelectorAll(sel);
814
+ elements.forEach((el) => {
815
+ el.style.outline = "3px solid red";
816
+ el.style.outlineOffset = "2px";
817
+ });
818
+ }, resolvedSelector);
819
+ console.log(`[DEBUG] Highlighted ${await page.locator(resolvedSelector).count()} element(s) matching "${resolvedSelector}"`);
820
+ }
821
+ );
822
+ }
823
+
824
+ // src/steps/ui.layout.ts
825
+ import { expect as expect3 } from "@playwright/test";
826
+ import { createBdd as createBdd12 } from "playwright-bdd";
827
+ function registerLayoutSteps(test) {
828
+ const { Given, When, Then } = createBdd12(test);
829
+ Then(
830
+ "I should see the {string} panel",
831
+ { tags: "@ui or @hybrid" },
832
+ async ({ page, world }, panelName) => {
833
+ const resolvedName = interpolate(panelName, world.vars);
834
+ const panel = page.getByTestId(`${resolvedName}-panel`);
835
+ await expect3(panel).toBeVisible();
836
+ }
837
+ );
838
+ Then(
839
+ "I should not see the {string} panel",
840
+ { tags: "@ui or @hybrid" },
841
+ async ({ page, world }, panelName) => {
842
+ const resolvedName = interpolate(panelName, world.vars);
843
+ const panel = page.getByTestId(`${resolvedName}-panel`);
844
+ await expect3(panel).toBeHidden();
845
+ }
846
+ );
847
+ Then(
848
+ "the {string} panel should be {string}",
849
+ { tags: "@ui or @hybrid" },
850
+ async ({ page, world }, panelName, state) => {
851
+ const resolvedName = interpolate(panelName, world.vars);
852
+ const panel = page.getByTestId(`${resolvedName}-panel`);
853
+ if (state === "visible") {
854
+ await expect3(panel).toBeVisible();
855
+ } else if (state === "hidden") {
856
+ await expect3(panel).toBeHidden();
857
+ } else {
858
+ throw new Error(`Unknown panel state: ${state}. Expected 'visible' or 'hidden'.`);
859
+ }
860
+ }
861
+ );
862
+ Then(
863
+ "the {string} panel should be full width",
864
+ { tags: "@ui or @hybrid" },
865
+ async ({ page, world }, panelName) => {
866
+ const resolvedName = interpolate(panelName, world.vars);
867
+ const panel = page.getByTestId(`${resolvedName}-panel`);
868
+ const isFullWidth = await panel.evaluate((el) => {
869
+ return !el.classList.contains("split") && !el.classList.contains("narrow") && !el.classList.contains("split-view-list");
870
+ });
871
+ expect3(isFullWidth, `Expected "${resolvedName}" panel to be full width`).toBe(true);
872
+ }
873
+ );
874
+ Then(
875
+ "the {string} panel should be narrow",
876
+ { tags: "@ui or @hybrid" },
877
+ async ({ page, world }, panelName) => {
878
+ const resolvedName = interpolate(panelName, world.vars);
879
+ const panel = page.getByTestId(`${resolvedName}-panel`);
880
+ const isNarrow = await panel.evaluate((el) => {
881
+ return el.classList.contains("split") || el.classList.contains("narrow") || el.classList.contains("split-view-list");
882
+ });
883
+ expect3(isNarrow, `Expected "${resolvedName}" panel to be narrow`).toBe(true);
884
+ }
885
+ );
886
+ Then(
887
+ "I should see a split view layout",
888
+ { tags: "@ui or @hybrid" },
889
+ async ({ page }) => {
890
+ const splitContainer = page.locator("[data-testid='split-view'], .split-view, [data-split-view]");
891
+ await expect3(splitContainer.first()).toBeVisible();
892
+ }
893
+ );
894
+ Then(
895
+ "I should not see a split view layout",
896
+ { tags: "@ui or @hybrid" },
897
+ async ({ page }) => {
898
+ const splitContainer = page.locator("[data-testid='split-view'], .split-view, [data-split-view]");
899
+ const count = await splitContainer.count();
900
+ expect3(count === 0 || !await splitContainer.first().isVisible()).toBe(true);
901
+ }
902
+ );
903
+ Then(
904
+ "the sidebar should be visible",
905
+ { tags: "@ui or @hybrid" },
906
+ async ({ page }) => {
907
+ const sidebar = page.locator("[data-testid='sidebar'], aside, nav.sidebar, .sidebar");
908
+ await expect3(sidebar.first()).toBeVisible();
909
+ }
910
+ );
911
+ Then(
912
+ "the sidebar should be hidden",
913
+ { tags: "@ui or @hybrid" },
914
+ async ({ page }) => {
915
+ const sidebar = page.locator("[data-testid='sidebar'], aside.sidebar, nav.sidebar");
916
+ const count = await sidebar.count();
917
+ if (count > 0) {
918
+ await expect3(sidebar.first()).toBeHidden();
919
+ }
920
+ }
921
+ );
922
+ Then(
923
+ "the sidebar should be collapsed",
924
+ { tags: "@ui or @hybrid" },
925
+ async ({ page }) => {
926
+ const sidebar = page.locator("[data-testid='sidebar'], aside, nav.sidebar, .sidebar").first();
927
+ const isCollapsed = await sidebar.evaluate((el) => {
928
+ return el.classList.contains("collapsed") || el.classList.contains("minimized") || el.getAttribute("data-collapsed") === "true";
929
+ });
930
+ expect3(isCollapsed, "Expected sidebar to be collapsed").toBe(true);
931
+ }
932
+ );
933
+ Then(
934
+ "I should see a modal dialog",
935
+ { tags: "@ui or @hybrid" },
936
+ async ({ page }) => {
937
+ const modal = page.locator("[role='dialog'], [data-testid='modal'], .modal, [aria-modal='true']");
938
+ await expect3(modal.first()).toBeVisible();
939
+ }
940
+ );
941
+ Then(
942
+ "I should not see a modal dialog",
943
+ { tags: "@ui or @hybrid" },
944
+ async ({ page }) => {
945
+ const modal = page.locator("[role='dialog'], [data-testid='modal'], .modal, [aria-modal='true']");
946
+ const count = await modal.count();
947
+ if (count > 0) {
948
+ await expect3(modal.first()).toBeHidden();
949
+ }
950
+ }
951
+ );
952
+ Then(
953
+ "I should see the {string} modal",
954
+ { tags: "@ui or @hybrid" },
955
+ async ({ page, world }, modalName) => {
956
+ const resolvedName = interpolate(modalName, world.vars);
957
+ const modal = page.getByTestId(`${resolvedName}-modal`);
958
+ await expect3(modal).toBeVisible();
959
+ }
960
+ );
961
+ Given(
962
+ "the viewport is {string} size",
963
+ { tags: "@ui or @hybrid" },
964
+ async ({ page }, sizeName) => {
965
+ const sizes = {
966
+ mobile: { width: 375, height: 667 },
967
+ tablet: { width: 768, height: 1024 },
968
+ desktop: { width: 1280, height: 800 },
969
+ "large-desktop": { width: 1920, height: 1080 }
970
+ };
971
+ const size = sizes[sizeName.toLowerCase()];
972
+ if (!size) {
973
+ throw new Error(`Unknown viewport size: ${sizeName}. Available: ${Object.keys(sizes).join(", ")}`);
974
+ }
975
+ await page.setViewportSize(size);
976
+ }
977
+ );
978
+ Given(
979
+ "the viewport is {int}x{int}",
980
+ { tags: "@ui or @hybrid" },
981
+ async ({ page }, width, height) => {
982
+ await page.setViewportSize({ width, height });
983
+ }
984
+ );
985
+ Then(
986
+ "the layout should be responsive",
987
+ { tags: "@ui or @hybrid" },
988
+ async ({ page }) => {
989
+ const original = page.viewportSize();
990
+ await page.setViewportSize({ width: 375, height: 667 });
991
+ await page.waitForTimeout(100);
992
+ await page.setViewportSize({ width: 1280, height: 800 });
993
+ await page.waitForTimeout(100);
994
+ if (original) {
995
+ await page.setViewportSize(original);
996
+ }
997
+ }
998
+ );
999
+ Then(
1000
+ "the {string} tab should be active",
1001
+ { tags: "@ui or @hybrid" },
1002
+ async ({ page, world }, tabName) => {
1003
+ const resolvedName = interpolate(tabName, world.vars);
1004
+ const tab = page.getByRole("tab", { name: resolvedName });
1005
+ await expect3(tab).toHaveAttribute("aria-selected", "true");
1006
+ }
1007
+ );
1008
+ Then(
1009
+ "the {string} tab should not be active",
1010
+ { tags: "@ui or @hybrid" },
1011
+ async ({ page, world }, tabName) => {
1012
+ const resolvedName = interpolate(tabName, world.vars);
1013
+ const tab = page.getByRole("tab", { name: resolvedName });
1014
+ await expect3(tab).toHaveAttribute("aria-selected", "false");
1015
+ }
1016
+ );
1017
+ When(
1018
+ "I click the {string} tab",
1019
+ { tags: "@ui or @hybrid" },
1020
+ async ({ page, world }, tabName) => {
1021
+ const resolvedName = interpolate(tabName, world.vars);
1022
+ const tab = page.getByRole("tab", { name: resolvedName });
1023
+ await tab.click();
1024
+ }
1025
+ );
1026
+ }
1027
+
1028
+ // src/steps/ui.auth.ts
1029
+ import { createBdd as createBdd13 } from "playwright-bdd";
1030
+
1031
+ // src/adapters/ui/fetch-intercept-auth.adapter.ts
1032
+ var defaultBypassConfig = {
1033
+ urlPattern: "/api/",
1034
+ headers: {
1035
+ "x-user-id": (data) => data.userId,
1036
+ "x-tenant-id": (data) => data.tenantId || "",
1037
+ "x-user-roles": (data) => data.roles.join(",")
1038
+ },
1039
+ localStorageKey: "mockAuth"
1040
+ };
1041
+ var defaultBearerConfig = {
1042
+ urlPattern: "/api/",
1043
+ headers: {
1044
+ Authorization: (data) => `Bearer ${data.token || ""}`
1045
+ }
1046
+ };
1047
+ async function setupFetchIntercept(page, authData, config = defaultBypassConfig) {
1048
+ const staticHeaders = {};
1049
+ for (const [key, value] of Object.entries(config.headers)) {
1050
+ staticHeaders[key] = typeof value === "function" ? value(authData) : value;
1051
+ }
1052
+ const headers = {};
1053
+ for (const [key, value] of Object.entries(staticHeaders)) {
1054
+ if (value) {
1055
+ headers[key] = value;
1056
+ }
1057
+ }
1058
+ const urlPattern = config.urlPattern instanceof RegExp ? config.urlPattern.source : config.urlPattern || "";
1059
+ await page.addInitScript(
1060
+ (params) => {
1061
+ if (params.localStorageKey) {
1062
+ localStorage.setItem(params.localStorageKey, JSON.stringify(params.authData));
1063
+ }
1064
+ const originalFetch = window.fetch;
1065
+ window.fetch = function(input, init) {
1066
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
1067
+ const shouldIntercept = !params.urlPattern || url.includes(params.urlPattern);
1068
+ if (shouldIntercept) {
1069
+ const modifiedInit = init || {};
1070
+ modifiedInit.headers = {
1071
+ ...modifiedInit.headers || {},
1072
+ ...params.headers
1073
+ };
1074
+ return originalFetch.call(this, input, modifiedInit);
1075
+ }
1076
+ return originalFetch.call(this, input, init);
1077
+ };
1078
+ },
1079
+ { authData, headers, urlPattern, localStorageKey: config.localStorageKey }
1080
+ );
1081
+ }
1082
+ async function clearFetchIntercept(page) {
1083
+ await page.reload();
1084
+ }
1085
+ async function setupBypassAuth(page, userId, roles, tenantId) {
1086
+ await setupFetchIntercept(page, { userId, roles, tenantId }, defaultBypassConfig);
1087
+ }
1088
+ async function setupBearerAuth(page, token) {
1089
+ await setupFetchIntercept(
1090
+ page,
1091
+ { userId: "", roles: [], token },
1092
+ defaultBearerConfig
1093
+ );
1094
+ }
1095
+
1096
+ // src/steps/ui.auth.ts
1097
+ function registerUiAuthSteps(test) {
1098
+ const { Given } = createBdd13(test);
1099
+ Given(
1100
+ "I am authenticated in UI as {string}",
1101
+ { tags: "@ui" },
1102
+ async ({ page, world }, rolesStr) => {
1103
+ const roles = rolesStr.split(",").map((r) => r.trim());
1104
+ const testRunId = world.testRunId || world.vars.test_run_id || Date.now();
1105
+ const userId = `test-user-${testRunId}`;
1106
+ const isAdmin = roles.includes("admin");
1107
+ const tenantId = isAdmin ? void 0 : "org-a";
1108
+ await setupBypassAuth(page, userId, roles, tenantId);
1109
+ world.vars.currentUserId = userId;
1110
+ world.vars.currentRoles = roles.join(",");
1111
+ if (tenantId) {
1112
+ world.vars.currentTenantId = tenantId;
1113
+ }
1114
+ console.log(`[BDD] UI authenticated as ${roles.join(", ")} (user: ${userId})`);
1115
+ }
1116
+ );
1117
+ Given(
1118
+ "I am authenticated in UI as {string} for tenant {string}",
1119
+ { tags: "@ui" },
1120
+ async ({ page, world }, rolesStr, tenantId) => {
1121
+ const roles = rolesStr.split(",").map((r) => r.trim());
1122
+ const testRunId = world.testRunId || world.vars.test_run_id || Date.now();
1123
+ const userId = `test-user-${testRunId}`;
1124
+ const resolvedTenantId = interpolate(tenantId, world.vars);
1125
+ await setupBypassAuth(page, userId, roles, resolvedTenantId);
1126
+ world.vars.currentUserId = userId;
1127
+ world.vars.currentTenantId = resolvedTenantId;
1128
+ world.vars.currentRoles = roles.join(",");
1129
+ console.log(`[BDD] UI authenticated as ${roles.join(", ")} for tenant ${resolvedTenantId}`);
1130
+ }
1131
+ );
1132
+ Given(
1133
+ "I am authenticated in UI as {string} with id {string}",
1134
+ { tags: "@ui" },
1135
+ async ({ page, world }, rolesStr, userId) => {
1136
+ const roles = rolesStr.split(",").map((r) => r.trim());
1137
+ const resolvedUserId = interpolate(userId, world.vars);
1138
+ const tenantId = "org-a";
1139
+ await setupBypassAuth(page, resolvedUserId, roles, tenantId);
1140
+ world.vars.currentUserId = resolvedUserId;
1141
+ world.vars.currentTenantId = tenantId;
1142
+ world.vars.currentRoles = roles.join(",");
1143
+ console.log(`[BDD] UI authenticated as ${roles.join(", ")} with id ${resolvedUserId}`);
1144
+ }
1145
+ );
1146
+ Given(
1147
+ "I am authenticated in UI with bearer token {string}",
1148
+ { tags: "@ui" },
1149
+ async ({ page, world }, token) => {
1150
+ const resolvedToken = interpolate(token, world.vars);
1151
+ await setupBearerAuth(page, resolvedToken);
1152
+ console.log("[BDD] UI authenticated with bearer token");
1153
+ }
1154
+ );
1155
+ Given(
1156
+ "I am authenticated in UI with headers:",
1157
+ { tags: "@ui" },
1158
+ async ({ page, world }, dataTable) => {
1159
+ const rows = dataTable.hashes ? dataTable.hashes() : dataTable.rawTable?.slice(1).map((row) => ({
1160
+ header: row[0],
1161
+ value: row[1]
1162
+ })) || [];
1163
+ const headers = {};
1164
+ for (const row of rows) {
1165
+ headers[row.header] = interpolate(row.value, world.vars);
1166
+ }
1167
+ await setupFetchIntercept(
1168
+ page,
1169
+ { userId: headers["x-user-id"] || "", roles: (headers["x-user-roles"] || "").split(","), tenantId: headers["x-tenant-id"] },
1170
+ {
1171
+ urlPattern: "/api/",
1172
+ headers,
1173
+ localStorageKey: "mockAuth"
1174
+ }
1175
+ );
1176
+ console.log(`[BDD] UI authenticated with custom headers: ${Object.keys(headers).join(", ")}`);
1177
+ }
1178
+ );
1179
+ Given(
1180
+ "I switch UI user to {string} with id {string}",
1181
+ { tags: "@ui" },
1182
+ async ({ page, world }, rolesStr, userId) => {
1183
+ const roles = rolesStr.split(",").map((r) => r.trim());
1184
+ const resolvedUserId = interpolate(userId, world.vars);
1185
+ const tenantId = world.vars.currentTenantId || "org-a";
1186
+ await page.reload();
1187
+ await setupBypassAuth(page, resolvedUserId, roles, tenantId);
1188
+ world.vars.currentUserId = resolvedUserId;
1189
+ world.vars.currentRoles = roles.join(",");
1190
+ console.log(`[BDD] UI switched to user ${resolvedUserId} with roles ${roles.join(", ")}`);
1191
+ }
1192
+ );
1193
+ }
1194
+
513
1195
  // src/steps/tui.basic.ts
514
- import { createBdd as createBdd9 } from "playwright-bdd";
1196
+ import { createBdd as createBdd14 } from "playwright-bdd";
515
1197
  function registerTuiBasicSteps(test) {
516
- const { Given, When, Then } = createBdd9(test);
1198
+ const { Given, When, Then } = createBdd14(test);
517
1199
  Given("I start the TUI application", { tags: "@tui" }, async ({ tui }) => {
518
1200
  await tui.start();
519
1201
  await tui.waitForReady();
@@ -634,9 +1316,9 @@ ${result.diff || "No diff available"}`);
634
1316
  }
635
1317
 
636
1318
  // src/steps/tui.wizard.ts
637
- import { createBdd as createBdd10 } from "playwright-bdd";
1319
+ import { createBdd as createBdd15 } from "playwright-bdd";
638
1320
  function registerTuiWizardSteps(test) {
639
- const { Given, When, Then } = createBdd10(test);
1321
+ const { Given, When, Then } = createBdd15(test);
640
1322
  When("I navigate down {int} times", { tags: "@tui" }, async ({ tui }, times) => {
641
1323
  for (let i = 0; i < times; i++) {
642
1324
  await tui.pressKey("down");
@@ -789,10 +1471,15 @@ function registerApiSteps(test) {
789
1471
  function registerUiSteps(test) {
790
1472
  registerUiBasicSteps(test);
791
1473
  registerWizardSteps(test);
1474
+ registerFormSteps(test);
1475
+ registerDebugSteps(test);
1476
+ registerLayoutSteps(test);
1477
+ registerUiAuthSteps(test);
792
1478
  }
793
1479
  function registerSharedSteps(test) {
794
1480
  registerSharedVarSteps(test);
795
1481
  registerSharedCleanupSteps(test);
1482
+ registerFlagSteps(test);
796
1483
  }
797
1484
  function registerHybridSuite(test) {
798
1485
  registerHybridSteps(test);
@@ -801,6 +1488,13 @@ function registerTuiSteps(test) {
801
1488
  registerTuiBasicSteps(test);
802
1489
  registerTuiWizardSteps(test);
803
1490
  }
1491
+ function registerAllSteps(test) {
1492
+ registerApiSteps(test);
1493
+ registerUiSteps(test);
1494
+ registerTuiSteps(test);
1495
+ registerSharedSteps(test);
1496
+ registerHybridSuite(test);
1497
+ }
804
1498
 
805
1499
  export {
806
1500
  interpolate,
@@ -809,19 +1503,33 @@ export {
809
1503
  parseExpected,
810
1504
  assertMasked,
811
1505
  registerCleanup,
1506
+ defaultBypassConfig,
1507
+ defaultBearerConfig,
1508
+ setupFetchIntercept,
1509
+ clearFetchIntercept,
1510
+ setupBypassAuth,
1511
+ setupBearerAuth,
812
1512
  registerApiHttpSteps,
813
1513
  registerApiAssertionSteps,
814
1514
  registerApiAuthSteps,
815
1515
  registerHybridSteps,
816
1516
  registerSharedCleanupSteps,
817
1517
  registerSharedVarSteps,
1518
+ isFlagEnabled,
1519
+ setFlag,
1520
+ registerFlagSteps,
818
1521
  registerUiBasicSteps,
819
1522
  registerWizardSteps,
1523
+ registerFormSteps,
1524
+ registerDebugSteps,
1525
+ registerLayoutSteps,
1526
+ registerUiAuthSteps,
820
1527
  registerTuiBasicSteps,
821
1528
  registerTuiWizardSteps,
822
1529
  registerApiSteps,
823
1530
  registerUiSteps,
824
1531
  registerSharedSteps,
825
1532
  registerHybridSuite,
826
- registerTuiSteps
1533
+ registerTuiSteps,
1534
+ registerAllSteps
827
1535
  };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as playwright_bdd from 'playwright-bdd';
2
2
  export { test as baseTest } from 'playwright-bdd';
3
3
  import * as _playwright_test from '@playwright/test';
4
4
  import { APIResponse, PlaywrightTestArgs, PlaywrightWorkerArgs, APIRequestContext, Page } from '@playwright/test';
5
- export { registerApiAssertionSteps, registerApiAuthSteps, registerApiHttpSteps, registerApiSteps, registerHybridSteps, registerHybridSuite, registerSharedCleanupSteps, registerSharedSteps, registerSharedVarSteps, registerTuiBasicSteps, registerTuiSteps, registerTuiWizardSteps, registerUiBasicSteps, registerUiSteps, registerWizardSteps } from './steps/index.js';
5
+ export { isFlagEnabled, registerAllSteps, registerApiAssertionSteps, registerApiAuthSteps, registerApiHttpSteps, registerApiSteps, registerDebugSteps, registerFlagSteps, registerFormSteps, registerHybridSteps, registerHybridSuite, registerLayoutSteps, registerSharedCleanupSteps, registerSharedSteps, registerSharedVarSteps, registerTuiBasicSteps, registerTuiSteps, registerTuiWizardSteps, registerUiAuthSteps, registerUiBasicSteps, registerUiSteps, registerWizardSteps, setFlag } from './steps/index.js';
6
6
 
7
7
  type CleanupItem = {
8
8
  method: 'DELETE' | 'POST' | 'PATCH' | 'PUT';
@@ -529,6 +529,64 @@ declare class TuiTesterAdapter implements TuiPort {
529
529
  getConfig(): TuiConfig;
530
530
  }
531
531
 
532
+ /**
533
+ * Fetch Intercept Auth Adapter
534
+ *
535
+ * Provides UI authentication by intercepting fetch requests and injecting headers.
536
+ * Useful for testing UIs that communicate with APIs using fetch.
537
+ */
538
+
539
+ interface FetchInterceptAuthData {
540
+ userId: string;
541
+ tenantId?: string;
542
+ roles: string[];
543
+ token?: string;
544
+ }
545
+ interface FetchInterceptConfig {
546
+ /**
547
+ * URL pattern to match for header injection.
548
+ * If not provided, headers are added to all fetch requests.
549
+ */
550
+ urlPattern?: string | RegExp;
551
+ /**
552
+ * Headers to inject. Can be static values or functions that receive auth data.
553
+ */
554
+ headers: Record<string, string | ((data: FetchInterceptAuthData) => string)>;
555
+ /**
556
+ * Key in localStorage to store auth data for UI components to read.
557
+ */
558
+ localStorageKey?: string;
559
+ }
560
+ /**
561
+ * Default configuration for bypass auth mode.
562
+ */
563
+ declare const defaultBypassConfig: FetchInterceptConfig;
564
+ /**
565
+ * Default configuration for bearer token auth.
566
+ */
567
+ declare const defaultBearerConfig: FetchInterceptConfig;
568
+ /**
569
+ * Set up fetch interception on a page.
570
+ *
571
+ * @param page - Playwright page
572
+ * @param authData - Authentication data to inject
573
+ * @param config - Configuration for interception
574
+ */
575
+ declare function setupFetchIntercept(page: Page, authData: FetchInterceptAuthData, config?: FetchInterceptConfig): Promise<void>;
576
+ /**
577
+ * Clear fetch interception setup (by reloading the page).
578
+ * Note: There's no clean way to remove addInitScript, so we reload.
579
+ */
580
+ declare function clearFetchIntercept(page: Page): Promise<void>;
581
+ /**
582
+ * Helper to set up bypass auth for a page.
583
+ */
584
+ declare function setupBypassAuth(page: Page, userId: string, roles: string[], tenantId?: string): Promise<void>;
585
+ /**
586
+ * Helper to set up bearer token auth for a page.
587
+ */
588
+ declare function setupBearerAuth(page: Page, token: string): Promise<void>;
589
+
532
590
  type TagsForProjectInput = {
533
591
  projectTag: string;
534
592
  extraTags?: string;
@@ -537,4 +595,4 @@ type TagsForProjectInput = {
537
595
  declare function tagsForProject({ projectTag, extraTags, defaultExcludes }: TagsForProjectInput): string;
538
596
  declare function resolveExtraTags(raw?: string | null): string | undefined;
539
597
 
540
- export { type ApiMethod, type ApiPort, type ApiResult, type AuthPort, type CleanupItem, type CleanupPort, type CleanupRule, type CreateBddTestOptions, DefaultCleanupAdapter, PlaywrightApiAdapter, PlaywrightUiAdapter, type TuiConfig, type TuiFactory, type TuiKeyModifiers, type TuiMouseButton, type TuiMouseEvent, type TuiMouseEventType, type TuiPort, type TuiScreenCapture, type TuiSnapshotResult, TuiTesterAdapter, type TuiWaitOptions, type UiClickMode, type UiElementState, type UiInputMode, type UiLocatorMethod, type UiPort, type UiUrlAssertMode, UniversalAuthAdapter, type World, assertMasked, createBddTest, initWorld, interpolate, parseExpected, registerCleanup, resolveExtraTags, selectPath, tagsForProject, tryParseJson };
598
+ export { type ApiMethod, type ApiPort, type ApiResult, type AuthPort, type CleanupItem, type CleanupPort, type CleanupRule, type CreateBddTestOptions, DefaultCleanupAdapter, type FetchInterceptAuthData, type FetchInterceptConfig, PlaywrightApiAdapter, PlaywrightUiAdapter, type TuiConfig, type TuiFactory, type TuiKeyModifiers, type TuiMouseButton, type TuiMouseEvent, type TuiMouseEventType, type TuiPort, type TuiScreenCapture, type TuiSnapshotResult, TuiTesterAdapter, type TuiWaitOptions, type UiClickMode, type UiElementState, type UiInputMode, type UiLocatorMethod, type UiPort, type UiUrlAssertMode, UniversalAuthAdapter, type World, assertMasked, clearFetchIntercept, createBddTest, defaultBearerConfig, defaultBypassConfig, initWorld, interpolate, parseExpected, registerCleanup, resolveExtraTags, selectPath, setupBearerAuth, setupBypassAuth, setupFetchIntercept, tagsForProject, tryParseJson };
package/dist/index.js CHANGED
@@ -1,26 +1,40 @@
1
1
  import {
2
2
  assertMasked,
3
+ clearFetchIntercept,
4
+ defaultBearerConfig,
5
+ defaultBypassConfig,
3
6
  interpolate,
7
+ isFlagEnabled,
4
8
  parseExpected,
9
+ registerAllSteps,
5
10
  registerApiAssertionSteps,
6
11
  registerApiAuthSteps,
7
12
  registerApiHttpSteps,
8
13
  registerApiSteps,
9
14
  registerCleanup,
15
+ registerDebugSteps,
16
+ registerFlagSteps,
17
+ registerFormSteps,
10
18
  registerHybridSteps,
11
19
  registerHybridSuite,
20
+ registerLayoutSteps,
12
21
  registerSharedCleanupSteps,
13
22
  registerSharedSteps,
14
23
  registerSharedVarSteps,
15
24
  registerTuiBasicSteps,
16
25
  registerTuiSteps,
17
26
  registerTuiWizardSteps,
27
+ registerUiAuthSteps,
18
28
  registerUiBasicSteps,
19
29
  registerUiSteps,
20
30
  registerWizardSteps,
21
31
  selectPath,
32
+ setFlag,
33
+ setupBearerAuth,
34
+ setupBypassAuth,
35
+ setupFetchIntercept,
22
36
  tryParseJson
23
- } from "./chunk-73J5FNGG.js";
37
+ } from "./chunk-VWBEMXYC.js";
24
38
 
25
39
  // src/fixtures.ts
26
40
  import { test as base } from "playwright-bdd";
@@ -854,28 +868,42 @@ export {
854
868
  UniversalAuthAdapter,
855
869
  assertMasked,
856
870
  base as baseTest,
871
+ clearFetchIntercept,
857
872
  createBddTest,
873
+ defaultBearerConfig,
874
+ defaultBypassConfig,
858
875
  initWorld,
859
876
  interpolate,
877
+ isFlagEnabled,
860
878
  parseExpected,
879
+ registerAllSteps,
861
880
  registerApiAssertionSteps,
862
881
  registerApiAuthSteps,
863
882
  registerApiHttpSteps,
864
883
  registerApiSteps,
865
884
  registerCleanup,
885
+ registerDebugSteps,
886
+ registerFlagSteps,
887
+ registerFormSteps,
866
888
  registerHybridSteps,
867
889
  registerHybridSuite,
890
+ registerLayoutSteps,
868
891
  registerSharedCleanupSteps,
869
892
  registerSharedSteps,
870
893
  registerSharedVarSteps,
871
894
  registerTuiBasicSteps,
872
895
  registerTuiSteps,
873
896
  registerTuiWizardSteps,
897
+ registerUiAuthSteps,
874
898
  registerUiBasicSteps,
875
899
  registerUiSteps,
876
900
  registerWizardSteps,
877
901
  resolveExtraTags,
878
902
  selectPath,
903
+ setFlag,
904
+ setupBearerAuth,
905
+ setupBypassAuth,
906
+ setupFetchIntercept,
879
907
  tagsForProject,
880
908
  tryParseJson
881
909
  };
@@ -10,10 +10,60 @@ declare function registerSharedCleanupSteps(test: any): void;
10
10
 
11
11
  declare function registerSharedVarSteps(test: any): void;
12
12
 
13
+ /**
14
+ * Feature Flag Step Definitions
15
+ *
16
+ * Steps for managing feature flags in tests.
17
+ * These steps store flag state in the world object for use in other steps.
18
+ */
19
+ /**
20
+ * Check if a feature flag is enabled.
21
+ * Can be used by other steps for conditional logic.
22
+ */
23
+ declare function isFlagEnabled(world: any, flagName: string): boolean;
24
+ /**
25
+ * Set a feature flag value.
26
+ * Can be used programmatically by other steps or adapters.
27
+ */
28
+ declare function setFlag(world: any, flagName: string, enabled: boolean): void;
29
+ declare function registerFlagSteps(test: any): void;
30
+
13
31
  declare function registerUiBasicSteps(test: any): void;
14
32
 
15
33
  declare function registerWizardSteps(test: any): void;
16
34
 
35
+ /**
36
+ * UI Form Step Definitions
37
+ *
38
+ * Steps for bulk form filling using Gherkin data tables.
39
+ * Tagged with @ui or @hybrid for selective execution.
40
+ */
41
+ declare function registerFormSteps(test: any): void;
42
+
43
+ /**
44
+ * UI Debug Step Definitions
45
+ *
46
+ * Steps for debugging and troubleshooting UI tests.
47
+ * Tagged with @ui or @hybrid for selective execution.
48
+ */
49
+ declare function registerDebugSteps(test: any): void;
50
+
51
+ /**
52
+ * UI Layout Assertion Step Definitions
53
+ *
54
+ * Steps for asserting layout states like panels, split views, and responsive behavior.
55
+ * Tagged with @ui or @hybrid for selective execution.
56
+ */
57
+ declare function registerLayoutSteps(test: any): void;
58
+
59
+ /**
60
+ * UI Auth Step Definitions
61
+ *
62
+ * Steps for authenticating in UI tests using fetch interception.
63
+ * Tagged with @ui for selective execution.
64
+ */
65
+ declare function registerUiAuthSteps(test: any): void;
66
+
17
67
  /**
18
68
  * TUI Basic Step Definitions
19
69
  *
@@ -32,9 +82,37 @@ declare function registerTuiBasicSteps(test: any): void;
32
82
  */
33
83
  declare function registerTuiWizardSteps(test: any): void;
34
84
 
85
+ /**
86
+ * Register all API step definitions.
87
+ * Steps are tagged with @api or @hybrid for selective execution.
88
+ */
35
89
  declare function registerApiSteps(test: any): void;
90
+ /**
91
+ * Register all UI step definitions.
92
+ * Steps are tagged with @ui or @hybrid for selective execution.
93
+ *
94
+ * Includes:
95
+ * - Basic UI steps (navigation, clicks, fills)
96
+ * - Wizard steps (advanced interactions, locators, assertions)
97
+ * - Form steps (bulk form filling)
98
+ * - Debug steps (debugging utilities)
99
+ * - Layout steps (panel, split view, responsive assertions)
100
+ * - Auth steps (fetch interception auth)
101
+ */
36
102
  declare function registerUiSteps(test: any): void;
103
+ /**
104
+ * Register shared step definitions (used by all test types).
105
+ *
106
+ * Includes:
107
+ * - Variable management steps
108
+ * - Cleanup steps
109
+ * - Feature flag steps
110
+ */
37
111
  declare function registerSharedSteps(test: any): void;
112
+ /**
113
+ * Register hybrid step definitions.
114
+ * Steps that work with both API and UI in the same scenario.
115
+ */
38
116
  declare function registerHybridSuite(test: any): void;
39
117
  /**
40
118
  * Register all TUI (Terminal User Interface) step definitions.
@@ -42,7 +120,7 @@ declare function registerHybridSuite(test: any): void;
42
120
  *
43
121
  * @example
44
122
  * ```typescript
45
- * import { createBddTest, registerTuiSteps, TuiTesterAdapter } from '@kata/stack-tests';
123
+ * import { createBddTest, registerTuiSteps, TuiTesterAdapter } from '@esimplicity/stack-tests';
46
124
  *
47
125
  * const test = createBddTest({
48
126
  * createTui: () => new TuiTesterAdapter({
@@ -54,5 +132,20 @@ declare function registerHybridSuite(test: any): void;
54
132
  * ```
55
133
  */
56
134
  declare function registerTuiSteps(test: any): void;
135
+ /**
136
+ * Register all step definitions for a full-featured test suite.
137
+ * This is a convenience function that registers API, UI, TUI, Shared, and Hybrid steps.
138
+ *
139
+ * Note: TUI steps require the optional `tui-tester` peer dependency.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * import { createBddTest, registerAllSteps } from '@esimplicity/stack-tests';
144
+ *
145
+ * const test = createBddTest({ ... });
146
+ * registerAllSteps(test);
147
+ * ```
148
+ */
149
+ declare function registerAllSteps(test: any): void;
57
150
 
58
- export { registerApiAssertionSteps, registerApiAuthSteps, registerApiHttpSteps, registerApiSteps, registerHybridSteps, registerHybridSuite, registerSharedCleanupSteps, registerSharedSteps, registerSharedVarSteps, registerTuiBasicSteps, registerTuiSteps, registerTuiWizardSteps, registerUiBasicSteps, registerUiSteps, registerWizardSteps };
151
+ export { isFlagEnabled, registerAllSteps, registerApiAssertionSteps, registerApiAuthSteps, registerApiHttpSteps, registerApiSteps, registerDebugSteps, registerFlagSteps, registerFormSteps, registerHybridSteps, registerHybridSuite, registerLayoutSteps, registerSharedCleanupSteps, registerSharedSteps, registerSharedVarSteps, registerTuiBasicSteps, registerTuiSteps, registerTuiWizardSteps, registerUiAuthSteps, registerUiBasicSteps, registerUiSteps, registerWizardSteps, setFlag };
@@ -1,34 +1,50 @@
1
1
  import {
2
+ isFlagEnabled,
3
+ registerAllSteps,
2
4
  registerApiAssertionSteps,
3
5
  registerApiAuthSteps,
4
6
  registerApiHttpSteps,
5
7
  registerApiSteps,
8
+ registerDebugSteps,
9
+ registerFlagSteps,
10
+ registerFormSteps,
6
11
  registerHybridSteps,
7
12
  registerHybridSuite,
13
+ registerLayoutSteps,
8
14
  registerSharedCleanupSteps,
9
15
  registerSharedSteps,
10
16
  registerSharedVarSteps,
11
17
  registerTuiBasicSteps,
12
18
  registerTuiSteps,
13
19
  registerTuiWizardSteps,
20
+ registerUiAuthSteps,
14
21
  registerUiBasicSteps,
15
22
  registerUiSteps,
16
- registerWizardSteps
17
- } from "../chunk-73J5FNGG.js";
23
+ registerWizardSteps,
24
+ setFlag
25
+ } from "../chunk-VWBEMXYC.js";
18
26
  export {
27
+ isFlagEnabled,
28
+ registerAllSteps,
19
29
  registerApiAssertionSteps,
20
30
  registerApiAuthSteps,
21
31
  registerApiHttpSteps,
22
32
  registerApiSteps,
33
+ registerDebugSteps,
34
+ registerFlagSteps,
35
+ registerFormSteps,
23
36
  registerHybridSteps,
24
37
  registerHybridSuite,
38
+ registerLayoutSteps,
25
39
  registerSharedCleanupSteps,
26
40
  registerSharedSteps,
27
41
  registerSharedVarSteps,
28
42
  registerTuiBasicSteps,
29
43
  registerTuiSteps,
30
44
  registerTuiWizardSteps,
45
+ registerUiAuthSteps,
31
46
  registerUiBasicSteps,
32
47
  registerUiSteps,
33
- registerWizardSteps
48
+ registerWizardSteps,
49
+ setFlag
34
50
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esimplicity/stack-tests",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -78,7 +78,7 @@ function main() {
78
78
  }
79
79
 
80
80
  // Always show success message
81
- console.log(`${GREEN}${BOLD}@esimplicityinc/stack-tests${RESET} installed successfully!`);
81
+ console.log(`${GREEN}${BOLD}@esimplicity/stack-tests${RESET} installed successfully!`);
82
82
  console.log('');
83
83
  }
84
84