@testspectra/cli 1.0.16 → 1.0.17

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.
Files changed (32) hide show
  1. package/dist/types/generator.d.ts +2 -1
  2. package/dist/types/generator.js +108 -27
  3. package/package.json +1 -1
  4. package/templates/nx/modules/auth/e2e/.testspectra/types/android.d.ts +3 -0
  5. package/templates/nx/modules/auth/e2e/.testspectra/types/common.d.ts +3 -0
  6. package/templates/nx/modules/auth/e2e/.testspectra/types/fixtures.d.ts +1 -0
  7. package/templates/nx/modules/auth/e2e/.testspectra/types/ios.d.ts +3 -0
  8. package/templates/nx/modules/auth/e2e/.testspectra/types/mobile.d.ts +3 -0
  9. package/templates/nx/modules/auth/e2e/.testspectra/types/web.d.ts +3 -0
  10. package/templates/nx/modules/auth/e2e/package.json +1 -0
  11. package/templates/nx/modules/auth/e2e/specs/Auth/TC-AUTH-01/web.test.ts +10 -4
  12. package/templates/nx/modules/auth/e2e/tsconfig.android.tsbuildinfo +1 -1
  13. package/templates/nx/modules/auth/e2e/tsconfig.ios.tsbuildinfo +1 -1
  14. package/templates/nx/modules/auth/e2e/tsconfig.web.tsbuildinfo +1 -1
  15. package/templates/nx/modules/catalog/e2e/.testspectra/types/android.d.ts +3 -0
  16. package/templates/nx/modules/catalog/e2e/.testspectra/types/common.d.ts +3 -0
  17. package/templates/nx/modules/catalog/e2e/.testspectra/types/fixtures.d.ts +1 -0
  18. package/templates/nx/modules/catalog/e2e/.testspectra/types/ios.d.ts +3 -0
  19. package/templates/nx/modules/catalog/e2e/.testspectra/types/mobile.d.ts +3 -0
  20. package/templates/nx/modules/catalog/e2e/.testspectra/types/web.d.ts +3 -0
  21. package/templates/nx/modules/catalog/e2e/tsconfig.android.tsbuildinfo +1 -1
  22. package/templates/nx/modules/catalog/e2e/tsconfig.ios.tsbuildinfo +1 -1
  23. package/templates/nx/modules/catalog/e2e/tsconfig.web.tsbuildinfo +1 -1
  24. package/templates/nx/node_modules/.svelte2tsx-language-server-files/svelte-native-jsx.d.ts +32 -0
  25. package/templates/nx/node_modules/.svelte2tsx-language-server-files/svelte-shims-v4.d.ts +290 -0
  26. package/templates/nx/shared/testing/actions/dismissBanner/common.action.ts +6 -0
  27. package/templates/nx/shared/testing/fixtures/appConfig.json +4 -0
  28. package/templates/nx/shared/testing/page-objects/NavigationBar/common.ts +13 -0
  29. package/templates/nx/shared/testing/steps/loginAsAdmin/common.step.ts +3 -0
  30. package/templates/nx/shared/testing/tsconfig.json +9 -5
  31. package/templates/nx/shared/testing/tsconfig.tsbuildinfo +1 -1
  32. package/templates/nx/shared/testing/src/index.ts +0 -5
@@ -1,6 +1,7 @@
1
1
  export type PlatformTarget = "web" | "android" | "ios" | "mobile" | "common";
2
2
  export declare class TypeGenerator {
3
- static getPageObjectsDir(cwd: string): string;
3
+ static getPageObjectsDirs(cwd: string): string[];
4
+ static getEntityDirs(cwd: string, entityType: "actions" | "steps" | "fixtures"): string[];
4
5
  static generateAmbientDeclarations(cwd: string): Record<string, string>;
5
6
  static generateFixturesDeclaration(cwd: string): string;
6
7
  static writeDeclarationFiles(cwd: string): void;
@@ -8,17 +8,52 @@ const PLATFORM_HIERARCHY = {
8
8
  common: ["common"],
9
9
  };
10
10
  export class TypeGenerator {
11
- static getPageObjectsDir(cwd) {
11
+ static getPageObjectsDirs(cwd) {
12
+ const dirs = [];
12
13
  const p1 = path.join(cwd, "page-objects");
14
+ const p2 = path.join(cwd, "pageobjects");
13
15
  if (fs.existsSync(p1))
14
- return p1;
15
- return path.join(cwd, "pageobjects");
16
+ dirs.push(p1);
17
+ else if (fs.existsSync(p2))
18
+ dirs.push(p2);
19
+ // Look for shared directories in monorepo root
20
+ let cur = cwd;
21
+ while (cur !== path.dirname(cur)) {
22
+ const sharedTestingPo = path.join(cur, "shared/testing/page-objects");
23
+ const sharedPo = path.join(cur, "shared/page-objects");
24
+ if (fs.existsSync(sharedTestingPo) && !dirs.includes(sharedTestingPo))
25
+ dirs.push(sharedTestingPo);
26
+ if (fs.existsSync(sharedPo) && !dirs.includes(sharedPo))
27
+ dirs.push(sharedPo);
28
+ if (fs.existsSync(path.join(cur, "pnpm-workspace.yaml")) || fs.existsSync(path.join(cur, "nx.json")))
29
+ break;
30
+ cur = path.dirname(cur);
31
+ }
32
+ return dirs;
33
+ }
34
+ static getEntityDirs(cwd, entityType) {
35
+ const dirs = [];
36
+ const local = path.join(cwd, entityType);
37
+ if (fs.existsSync(local))
38
+ dirs.push(local);
39
+ let cur = cwd;
40
+ while (cur !== path.dirname(cur)) {
41
+ const sharedTesting = path.join(cur, "shared/testing", entityType);
42
+ const shared = path.join(cur, "shared", entityType);
43
+ if (fs.existsSync(sharedTesting) && !dirs.includes(sharedTesting))
44
+ dirs.push(sharedTesting);
45
+ if (fs.existsSync(shared) && !dirs.includes(shared))
46
+ dirs.push(shared);
47
+ if (fs.existsSync(path.join(cur, "pnpm-workspace.yaml")) || fs.existsSync(path.join(cur, "nx.json")))
48
+ break;
49
+ cur = path.dirname(cur);
50
+ }
51
+ return dirs;
16
52
  }
17
53
  static generateAmbientDeclarations(cwd) {
18
- const poDir = this.getPageObjectsDir(cwd);
19
- const actionsDir = path.join(cwd, "actions");
20
- const stepsDir = path.join(cwd, "steps");
21
- const fixturesDir = path.join(cwd, "fixtures");
54
+ const poDirs = this.getPageObjectsDirs(cwd);
55
+ const actionsDirs = this.getEntityDirs(cwd, "actions");
56
+ const stepsDirs = this.getEntityDirs(cwd, "steps");
22
57
  const platforms = ["web", "android", "ios", "mobile", "common"];
23
58
  const results = {};
24
59
  for (const platform of platforms) {
@@ -82,108 +117,148 @@ export class TypeGenerator {
82
117
  content += ` shouldHaveClass(this: Promise<WebdriverIO.Element>, className: string): Promise<WebdriverIO.Element>;\n`;
83
118
  content += ` shouldHaveAttribute(this: Promise<WebdriverIO.Element>, attributeName: string, expectedValue?: string): Promise<WebdriverIO.Element>;\n`;
84
119
  content += `}\n\n`;
85
- // 1. Page Objects Global Declarations (Hierarchical)
86
- // 2. Page Objects Global Declarations (Hierarchical)
87
- if (fs.existsSync(poDir)) {
120
+ // 1. Page Objects Global Declarations (Local + Shared Hierarchical)
121
+ const declaredPOMs = new Set();
122
+ for (const poDir of poDirs) {
123
+ if (!fs.existsSync(poDir))
124
+ continue;
88
125
  const poEntries = fs.readdirSync(poDir, { withFileTypes: true });
89
126
  for (const entry of poEntries) {
90
127
  if (entry.name.startsWith("."))
91
128
  continue;
92
129
  if (entry.isDirectory()) {
93
130
  const className = entry.name;
131
+ if (declaredPOMs.has(className))
132
+ continue;
94
133
  const classFolder = path.join(poDir, className);
95
- // Search hierarchy
96
134
  let matchedFile = null;
97
135
  for (const stem of hierarchy) {
98
136
  const cand = path.join(classFolder, `${stem}.ts`);
99
137
  if (fs.existsSync(cand)) {
100
- matchedFile = `../../page-objects/${className}/${stem}.js`;
138
+ matchedFile = path.relative(path.join(cwd, ".testspectra/types"), cand).replace(/\\/g, "/").replace(/\.ts$/, ".js");
139
+ if (!matchedFile.startsWith("."))
140
+ matchedFile = `./${matchedFile}`;
101
141
  break;
102
142
  }
103
143
  }
104
144
  if (matchedFile) {
105
145
  content += `declare const ${className}: typeof import('${matchedFile}').default;\n`;
146
+ declaredPOMs.add(className);
106
147
  }
107
148
  }
108
149
  else if (entry.isFile() && entry.name.endsWith(".ts")) {
109
150
  const className = entry.name.split(".")[0];
110
- content += `declare const ${className}: typeof import('../../page-objects/${entry.name.replace(".ts", ".js")}').default;\n`;
151
+ if (declaredPOMs.has(className))
152
+ continue;
153
+ let rel = path.relative(path.join(cwd, ".testspectra/types"), path.join(poDir, entry.name)).replace(/\\/g, "/").replace(/\.ts$/, ".js");
154
+ if (!rel.startsWith("."))
155
+ rel = `./${rel}`;
156
+ content += `declare const ${className}: typeof import('${rel}').default;\n`;
157
+ declaredPOMs.add(className);
111
158
  }
112
159
  }
113
160
  }
114
- // 3. Actions Global Interface (Extends built-in @testspectra/cli Spectra)
161
+ // 2. Actions Global Interface (Local + Shared)
115
162
  content += `\ninterface TestSpectraActions extends Omit<typeof import('@testspectra/cli').Spectra, ''> {\n`;
116
- if (fs.existsSync(actionsDir)) {
163
+ const declaredActions = new Set();
164
+ for (const actionsDir of actionsDirs) {
165
+ if (!fs.existsSync(actionsDir))
166
+ continue;
117
167
  const actionEntries = fs.readdirSync(actionsDir, { withFileTypes: true });
118
168
  for (const entry of actionEntries) {
119
169
  if (entry.name.startsWith("."))
120
170
  continue;
121
171
  if (entry.isDirectory()) {
122
172
  const actionName = entry.name;
173
+ if (declaredActions.has(actionName))
174
+ continue;
123
175
  const actionFolder = path.join(actionsDir, actionName);
124
176
  let matchedFile = null;
125
177
  for (const stem of hierarchy) {
126
178
  const cand1 = path.join(actionFolder, `${stem}.action.ts`);
127
179
  const cand2 = path.join(actionFolder, `${stem}.ts`);
128
180
  if (fs.existsSync(cand1)) {
129
- matchedFile = `../../actions/${actionName}/${stem}.action.js`;
181
+ matchedFile = path.relative(path.join(cwd, ".testspectra/types"), cand1).replace(/\\/g, "/").replace(/\.ts$/, ".js");
130
182
  break;
131
183
  }
132
184
  else if (fs.existsSync(cand2)) {
133
- matchedFile = `../../actions/${actionName}/${stem}.js`;
185
+ matchedFile = path.relative(path.join(cwd, ".testspectra/types"), cand2).replace(/\\/g, "/").replace(/\.ts$/, ".js");
134
186
  break;
135
187
  }
136
188
  }
137
189
  if (matchedFile) {
190
+ if (!matchedFile.startsWith("."))
191
+ matchedFile = `./${matchedFile}`;
138
192
  content += ` ${actionName}: (typeof import('${matchedFile}') extends { default: infer T } ? T : typeof import('${matchedFile}'));\n`;
193
+ declaredActions.add(actionName);
139
194
  }
140
195
  else {
141
196
  content += ` ${actionName}: (...args: any[]) => Promise<any>;\n`;
197
+ declaredActions.add(actionName);
142
198
  }
143
199
  }
144
200
  else if (entry.isFile() && entry.name.endsWith(".ts")) {
145
201
  const actionName = entry.name.split(".")[0];
146
- const modPath = `../../actions/${entry.name.replace(".ts", ".js")}`;
147
- content += ` ${actionName}: (typeof import('${modPath}') extends { default: infer T } ? T : typeof import('${modPath}'));\n`;
202
+ if (declaredActions.has(actionName))
203
+ continue;
204
+ let rel = path.relative(path.join(cwd, ".testspectra/types"), path.join(actionsDir, entry.name)).replace(/\\/g, "/").replace(/\.ts$/, ".js");
205
+ if (!rel.startsWith("."))
206
+ rel = `./${rel}`;
207
+ content += ` ${actionName}: (typeof import('${rel}') extends { default: infer T } ? T : typeof import('${rel}'));\n`;
208
+ declaredActions.add(actionName);
148
209
  }
149
210
  }
150
211
  }
151
212
  content += `}\n`;
152
213
  content += `declare const Spectra: TestSpectraActions;\n\n`;
153
- // 4. Shared Steps Global Interface
214
+ // 3. Shared Steps Global Interface (Local + Shared)
154
215
  content += `interface TestSpectraSteps {\n`;
155
- if (fs.existsSync(stepsDir)) {
216
+ const declaredSteps = new Set();
217
+ for (const stepsDir of stepsDirs) {
218
+ if (!fs.existsSync(stepsDir))
219
+ continue;
156
220
  const stepEntries = fs.readdirSync(stepsDir, { withFileTypes: true });
157
221
  for (const entry of stepEntries) {
158
222
  if (entry.name.startsWith("."))
159
223
  continue;
160
224
  if (entry.isDirectory()) {
161
225
  const stepName = entry.name;
226
+ if (declaredSteps.has(stepName))
227
+ continue;
162
228
  const stepFolder = path.join(stepsDir, stepName);
163
229
  let matchedFile = null;
164
230
  for (const stem of hierarchy) {
165
231
  const cand1 = path.join(stepFolder, `${stem}.step.ts`);
166
232
  const cand2 = path.join(stepFolder, `${stem}.ts`);
167
233
  if (fs.existsSync(cand1)) {
168
- matchedFile = `../../steps/${stepName}/${stem}.step.js`;
234
+ matchedFile = path.relative(path.join(cwd, ".testspectra/types"), cand1).replace(/\\/g, "/").replace(/\.ts$/, ".js");
169
235
  break;
170
236
  }
171
237
  else if (fs.existsSync(cand2)) {
172
- matchedFile = `../../steps/${stepName}/${stem}.js`;
238
+ matchedFile = path.relative(path.join(cwd, ".testspectra/types"), cand2).replace(/\\/g, "/").replace(/\.ts$/, ".js");
173
239
  break;
174
240
  }
175
241
  }
176
242
  if (matchedFile) {
243
+ if (!matchedFile.startsWith("."))
244
+ matchedFile = `./${matchedFile}`;
177
245
  content += ` ${stepName}: (typeof import('${matchedFile}') extends { default: infer T } ? T : typeof import('${matchedFile}'));\n`;
246
+ declaredSteps.add(stepName);
178
247
  }
179
248
  else {
180
249
  content += ` ${stepName}: (...args: any[]) => Promise<any>;\n`;
250
+ declaredSteps.add(stepName);
181
251
  }
182
252
  }
183
253
  else if (entry.isFile() && entry.name.endsWith(".ts")) {
184
254
  const stepName = entry.name.split(".")[0];
185
- const modPath = `../../steps/${entry.name.replace(".ts", ".js")}`;
186
- content += ` ${stepName}: (typeof import('${modPath}') extends { default: infer T } ? T : typeof import('${modPath}'));\n`;
255
+ if (declaredSteps.has(stepName))
256
+ continue;
257
+ let rel = path.relative(path.join(cwd, ".testspectra/types"), path.join(stepsDir, entry.name)).replace(/\\/g, "/").replace(/\.ts$/, ".js");
258
+ if (!rel.startsWith("."))
259
+ rel = `./${rel}`;
260
+ content += ` ${stepName}: (typeof import('${rel}') extends { default: infer T } ? T : typeof import('${rel}'));\n`;
261
+ declaredSteps.add(stepName);
187
262
  }
188
263
  }
189
264
  }
@@ -194,18 +269,24 @@ export class TypeGenerator {
194
269
  return results;
195
270
  }
196
271
  static generateFixturesDeclaration(cwd) {
197
- const fixturesDir = path.join(cwd, "fixtures");
272
+ const fixturesDirs = this.getEntityDirs(cwd, "fixtures");
198
273
  let content = `// Auto-generated ambient fixture declarations for TestSpectra\n`;
199
274
  content += `// Do not edit manually. Run 'spectra watch' or let the Language Service manage this.\n\n`;
200
275
  content += `interface TestSpectraFixtures {\n`;
201
- if (fs.existsSync(fixturesDir)) {
276
+ const declaredFixtures = new Set();
277
+ for (const fixturesDir of fixturesDirs) {
278
+ if (!fs.existsSync(fixturesDir))
279
+ continue;
202
280
  const fixtureFiles = fs.readdirSync(fixturesDir);
203
281
  for (const file of fixtureFiles) {
204
282
  if (file.startsWith("."))
205
283
  continue;
206
284
  const parsed = path.parse(file);
207
285
  const varName = parsed.name.replace(/[^a-zA-Z0-9_$]/g, "_");
286
+ if (declaredFixtures.has(varName))
287
+ continue;
208
288
  content += ` readonly ${varName}: string;\n`;
289
+ declaredFixtures.add(varName);
209
290
  }
210
291
  }
211
292
  content += `}\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testspectra/cli",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "TestSpectra Zero-Config Cross-Platform Test Runner CLI",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -64,16 +64,19 @@ interface Promise<T> {
64
64
  declare const LoginPage: typeof import('../../page-objects/LoginPage/mobile.js').default;
65
65
  declare const ProductPage: typeof import('../../page-objects/ProductPage/mobile.js').default;
66
66
  declare const SettingsPage: typeof import('../../page-objects/SettingsPage/common.js').default;
67
+ declare const NavigationBar: typeof import('../../../../../shared/testing/page-objects/NavigationBar/common.js').default;
67
68
 
68
69
  interface TestSpectraActions extends Omit<typeof import('@testspectra/cli').Spectra, ''> {
69
70
  applyDiscount: (typeof import('../../actions/applyDiscount/mobile.action.js') extends { default: infer T } ? T : typeof import('../../actions/applyDiscount/mobile.action.js'));
70
71
  verifyOtp: (typeof import('../../actions/verifyOtp/mobile.action.js') extends { default: infer T } ? T : typeof import('../../actions/verifyOtp/mobile.action.js'));
72
+ dismissBanner: (typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js'));
71
73
  }
72
74
  declare const Spectra: TestSpectraActions;
73
75
 
74
76
  interface TestSpectraSteps {
75
77
  loginUser: (typeof import('../../steps/loginUser/mobile.step.js') extends { default: infer T } ? T : typeof import('../../steps/loginUser/mobile.step.js'));
76
78
  searchProduct: (typeof import('../../steps/searchProduct/mobile.step.js') extends { default: infer T } ? T : typeof import('../../steps/searchProduct/mobile.step.js'));
79
+ loginAsAdmin: (typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js'));
77
80
  }
78
81
  declare const Step: TestSpectraSteps;
79
82
 
@@ -62,16 +62,19 @@ interface Promise<T> {
62
62
  }
63
63
 
64
64
  declare const SettingsPage: typeof import('../../page-objects/SettingsPage/common.js').default;
65
+ declare const NavigationBar: typeof import('../../../../../shared/testing/page-objects/NavigationBar/common.js').default;
65
66
 
66
67
  interface TestSpectraActions extends Omit<typeof import('@testspectra/cli').Spectra, ''> {
67
68
  applyDiscount: (...args: any[]) => Promise<any>;
68
69
  verifyOtp: (...args: any[]) => Promise<any>;
70
+ dismissBanner: (typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js'));
69
71
  }
70
72
  declare const Spectra: TestSpectraActions;
71
73
 
72
74
  interface TestSpectraSteps {
73
75
  loginUser: (...args: any[]) => Promise<any>;
74
76
  searchProduct: (...args: any[]) => Promise<any>;
77
+ loginAsAdmin: (typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js'));
75
78
  }
76
79
  declare const Step: TestSpectraSteps;
77
80
 
@@ -5,5 +5,6 @@ interface TestSpectraFixtures {
5
5
  readonly couponCode: string;
6
6
  readonly searchQuery: string;
7
7
  readonly userData: string;
8
+ readonly appConfig: string;
8
9
  }
9
10
  declare const Fixture: TestSpectraFixtures;
@@ -64,16 +64,19 @@ interface Promise<T> {
64
64
  declare const LoginPage: typeof import('../../page-objects/LoginPage/mobile.js').default;
65
65
  declare const ProductPage: typeof import('../../page-objects/ProductPage/mobile.js').default;
66
66
  declare const SettingsPage: typeof import('../../page-objects/SettingsPage/common.js').default;
67
+ declare const NavigationBar: typeof import('../../../../../shared/testing/page-objects/NavigationBar/common.js').default;
67
68
 
68
69
  interface TestSpectraActions extends Omit<typeof import('@testspectra/cli').Spectra, ''> {
69
70
  applyDiscount: (typeof import('../../actions/applyDiscount/mobile.action.js') extends { default: infer T } ? T : typeof import('../../actions/applyDiscount/mobile.action.js'));
70
71
  verifyOtp: (typeof import('../../actions/verifyOtp/mobile.action.js') extends { default: infer T } ? T : typeof import('../../actions/verifyOtp/mobile.action.js'));
72
+ dismissBanner: (typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js'));
71
73
  }
72
74
  declare const Spectra: TestSpectraActions;
73
75
 
74
76
  interface TestSpectraSteps {
75
77
  loginUser: (typeof import('../../steps/loginUser/mobile.step.js') extends { default: infer T } ? T : typeof import('../../steps/loginUser/mobile.step.js'));
76
78
  searchProduct: (typeof import('../../steps/searchProduct/mobile.step.js') extends { default: infer T } ? T : typeof import('../../steps/searchProduct/mobile.step.js'));
79
+ loginAsAdmin: (typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js'));
77
80
  }
78
81
  declare const Step: TestSpectraSteps;
79
82
 
@@ -64,16 +64,19 @@ interface Promise<T> {
64
64
  declare const LoginPage: typeof import('../../page-objects/LoginPage/mobile.js').default;
65
65
  declare const ProductPage: typeof import('../../page-objects/ProductPage/mobile.js').default;
66
66
  declare const SettingsPage: typeof import('../../page-objects/SettingsPage/common.js').default;
67
+ declare const NavigationBar: typeof import('../../../../../shared/testing/page-objects/NavigationBar/common.js').default;
67
68
 
68
69
  interface TestSpectraActions extends Omit<typeof import('@testspectra/cli').Spectra, ''> {
69
70
  applyDiscount: (typeof import('../../actions/applyDiscount/mobile.action.js') extends { default: infer T } ? T : typeof import('../../actions/applyDiscount/mobile.action.js'));
70
71
  verifyOtp: (typeof import('../../actions/verifyOtp/mobile.action.js') extends { default: infer T } ? T : typeof import('../../actions/verifyOtp/mobile.action.js'));
72
+ dismissBanner: (typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js'));
71
73
  }
72
74
  declare const Spectra: TestSpectraActions;
73
75
 
74
76
  interface TestSpectraSteps {
75
77
  loginUser: (typeof import('../../steps/loginUser/mobile.step.js') extends { default: infer T } ? T : typeof import('../../steps/loginUser/mobile.step.js'));
76
78
  searchProduct: (typeof import('../../steps/searchProduct/mobile.step.js') extends { default: infer T } ? T : typeof import('../../steps/searchProduct/mobile.step.js'));
79
+ loginAsAdmin: (typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js'));
77
80
  }
78
81
  declare const Step: TestSpectraSteps;
79
82
 
@@ -64,16 +64,19 @@ interface Promise<T> {
64
64
  declare const LoginPage: typeof import('../../page-objects/LoginPage/web.js').default;
65
65
  declare const ProductPage: typeof import('../../page-objects/ProductPage/web.js').default;
66
66
  declare const SettingsPage: typeof import('../../page-objects/SettingsPage/common.js').default;
67
+ declare const NavigationBar: typeof import('../../../../../shared/testing/page-objects/NavigationBar/common.js').default;
67
68
 
68
69
  interface TestSpectraActions extends Omit<typeof import('@testspectra/cli').Spectra, ''> {
69
70
  applyDiscount: (typeof import('../../actions/applyDiscount/web.action.js') extends { default: infer T } ? T : typeof import('../../actions/applyDiscount/web.action.js'));
70
71
  verifyOtp: (typeof import('../../actions/verifyOtp/web.action.js') extends { default: infer T } ? T : typeof import('../../actions/verifyOtp/web.action.js'));
72
+ dismissBanner: (typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/actions/dismissBanner/common.action.js'));
71
73
  }
72
74
  declare const Spectra: TestSpectraActions;
73
75
 
74
76
  interface TestSpectraSteps {
75
77
  loginUser: (typeof import('../../steps/loginUser/web.step.js') extends { default: infer T } ? T : typeof import('../../steps/loginUser/web.step.js'));
76
78
  searchProduct: (typeof import('../../steps/searchProduct/web.step.js') extends { default: infer T } ? T : typeof import('../../steps/searchProduct/web.step.js'));
79
+ loginAsAdmin: (typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js') extends { default: infer T } ? T : typeof import('../../../../../shared/testing/steps/loginAsAdmin/common.step.js'));
77
80
  }
78
81
  declare const Step: TestSpectraSteps;
79
82
 
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "devDependencies": {
11
11
  "@testspectra/cli": "workspace:*",
12
+ "@testspectra/shared-testing": "workspace:*",
12
13
  "@types/node": "^20.14.0",
13
14
  "@wdio/globals": "^9.2.8",
14
15
  "@wdio/mocha-framework": "^9.2.8",
@@ -1,13 +1,19 @@
1
1
  it("should authenticate user and verify flash message across specific platforms", async () => {
2
+ // 1. Global Fixtures (Module Fixture + Shared Workspace Fixture)
2
3
  await browser.intercept("/api/status", "GET", Fixture.userData);
3
4
 
4
- // 1. Navigation via Page Object
5
+ // 2. Global Shared Action from shared/testing (dismiss global banner if present)
6
+ await Spectra.dismissBanner();
7
+
8
+ // 3. Navigation via Module Page Object & Shared Page Object
9
+ await LoginPage.open();
10
+ await NavigationBar.goToHome();
5
11
  await LoginPage.open();
6
12
 
7
- // 2. High-level business flow via Shared Step & Page Object
8
- await Step.loginUser("tomsmith", "SuperSecretPassword!");
13
+ // 4. High-level business flow via Shared Step from shared/testing
14
+ await Step.loginAsAdmin();
9
15
 
10
- // 3. Direct callable assertion on Page Object element
16
+ // 5. Direct callable assertion on Page Object element
11
17
  await LoginPage.flashAlert.shouldBeVisible();
12
18
  await LoginPage.flashAlert.shouldContainText("You logged into a secure area!");
13
19
  });