@specwise/runner 0.1.0 → 0.2.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/dist/api.d.ts CHANGED
@@ -6,4 +6,6 @@ export declare class SpecwiseAPI {
6
6
  private request;
7
7
  pull(): Promise<PullResponse>;
8
8
  report(results: TestCaseReport[]): Promise<void>;
9
+ submitPage(projectId: string, data: unknown): Promise<void>;
10
+ submitFlow(projectId: string, data: unknown): Promise<void>;
9
11
  }
package/dist/api.js CHANGED
@@ -29,5 +29,11 @@ export class SpecwiseAPI {
29
29
  results,
30
30
  });
31
31
  }
32
+ async submitPage(projectId, data) {
33
+ await this.request("POST", `/api/v1/discovery/projects/${projectId}/pages`, data);
34
+ }
35
+ async submitFlow(projectId, data) {
36
+ await this.request("POST", `/api/v1/discovery/projects/${projectId}/flows`, data);
37
+ }
32
38
  }
33
39
  //# sourceMappingURL=api.js.map
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,WAAW;IAEZ;IACA;IAFV,YACU,OAAe,EACf,KAAa;QADb,YAAO,GAAP,OAAO,CAAQ;QACf,UAAK,GAAL,KAAK,CAAQ;IACpB,CAAC;IAEI,KAAK,CAAC,OAAO,CACnB,MAAc,EACd,IAAY,EACZ,IAAc;QAEd,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM;YACN,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;aACtC;YACD,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9C,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,IAAI,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,OAAO,CAAe,MAAM,EAAE,mCAAmC,CAAC,CAAC;IACjF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAyB;QACpC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,qCAAqC,EAAE;YAChE,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,WAAW;IAEZ;IACA;IAFV,YACU,OAAe,EACf,KAAa;QADb,YAAO,GAAP,OAAO,CAAQ;QACf,UAAK,GAAL,KAAK,CAAQ;IACpB,CAAC;IAEI,KAAK,CAAC,OAAO,CACnB,MAAc,EACd,IAAY,EACZ,IAAc;QAEd,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM;YACN,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;aACtC;YACD,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9C,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,IAAI,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,OAAO,CAAe,MAAM,EAAE,mCAAmC,CAAC,CAAC;IACjF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAyB;QACpC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,qCAAqC,EAAE;YAChE,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,IAAa;QAC/C,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,8BAA8B,SAAS,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpF,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,IAAa;QAC/C,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,8BAA8B,SAAS,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpF,CAAC;CACF"}
package/dist/cli.js CHANGED
@@ -1,11 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { SpecwiseAPI } from "./api.js";
3
3
  import { executeTestRun } from "./runner.js";
4
+ import { runDiscovery } from "./discoverer.js";
4
5
  import { log } from "./log.js";
5
6
  function parseArgs(argv) {
6
7
  let token = "";
7
8
  let api = "";
8
9
  let headed = false;
10
+ let discover = false;
11
+ let projectId = "";
12
+ let url = "";
9
13
  for (const arg of argv.slice(2)) {
10
14
  if (arg.startsWith("--token=")) {
11
15
  token = arg.slice("--token=".length);
@@ -13,43 +17,68 @@ function parseArgs(argv) {
13
17
  else if (arg.startsWith("--api=")) {
14
18
  api = arg.slice("--api=".length);
15
19
  }
20
+ else if (arg.startsWith("--project=")) {
21
+ projectId = arg.slice("--project=".length);
22
+ }
23
+ else if (arg.startsWith("--url=")) {
24
+ url = arg.slice("--url=".length);
25
+ }
16
26
  else if (arg === "--headed") {
17
27
  headed = true;
18
28
  }
29
+ else if (arg === "--discover") {
30
+ discover = true;
31
+ }
19
32
  else if (arg === "--help" || arg === "-h") {
20
33
  console.log(`
21
- @specwise/runner - Run Specwise tests locally with Playwright
34
+ @specwise/runner - Test runner and app discovery for Specwise
22
35
 
23
36
  Usage:
24
- npx @specwise/runner --token=<token> --api=<api_url>
37
+ npx @specwise/runner --token=<token> --api=<api_url> Run tests
38
+ npx @specwise/runner --discover --token=<token> --api=<url> \\
39
+ --project=<id> --url=<app_url> Discover app
40
+
41
+ Modes:
42
+ (default) Execute test cases from a test run
43
+ --discover Open browser, navigate your app, capture pages & elements
25
44
 
26
45
  Options:
27
- --token=<token> Execution token (from Specwise dashboard)
28
- --api=<url> Specwise API URL (e.g. http://localhost:8000)
29
- --headed Show browser window (default: headless)
30
- --help Show this help
46
+ --token=<token> Auth token (agent token for tests, access token for discovery)
47
+ --api=<url> Specwise API URL (e.g. http://localhost:8000)
48
+ --project=<id> Project ID (required for --discover)
49
+ --url=<url> Start URL for discovery (e.g. https://myapp.com)
50
+ --headed Show browser window (default for discover, optional for tests)
51
+ --help Show this help
31
52
  `);
32
53
  process.exit(0);
33
54
  }
34
55
  }
35
56
  if (!token) {
36
- console.error("Error: --token is required. Get one from the Specwise dashboard.");
57
+ console.error("Error: --token is required.");
37
58
  process.exit(1);
38
59
  }
39
60
  if (!api) {
40
61
  console.error("Error: --api is required. e.g. --api=http://localhost:8000");
41
62
  process.exit(1);
42
63
  }
43
- return { token, api: api.replace(/\/$/, ""), headed };
64
+ if (discover && !projectId) {
65
+ console.error("Error: --project is required for discovery mode.");
66
+ process.exit(1);
67
+ }
68
+ return { token, api: api.replace(/\/$/, ""), headed, discover, projectId, url };
44
69
  }
45
70
  async function main() {
46
- const { token, api, headed } = parseArgs(process.argv);
71
+ const args = parseArgs(process.argv);
47
72
  console.log("");
48
- console.log(" \x1b[1m@specwise/runner\x1b[0m v0.1.0");
73
+ console.log(" \x1b[1m@specwise/runner\x1b[0m v0.2.0");
49
74
  console.log(" ─────────────────────────");
50
75
  console.log("");
51
- const client = new SpecwiseAPI(api, token);
52
- // Pull test data
76
+ const client = new SpecwiseAPI(args.api, args.token);
77
+ if (args.discover) {
78
+ await runDiscovery(client, args.projectId, args.url);
79
+ return;
80
+ }
81
+ // ── Test execution mode ──────────────────────────────────────────────
53
82
  log("Pulling test cases from Specwise...");
54
83
  let data;
55
84
  try {
@@ -66,18 +95,15 @@ async function main() {
66
95
  log("No test cases to execute.");
67
96
  process.exit(0);
68
97
  }
69
- // Resolve test account
70
98
  const account = data.test_accounts[0] ?? null;
71
99
  if (account) {
72
100
  log(`Using account: ${account.label || account.email} (${account.role})`);
73
101
  }
74
- // Execute
75
102
  const reports = await executeTestRun(data.test_cases, {
76
103
  targetUrl: data.target_url,
77
104
  account,
78
105
  authConfig: data.auth_config,
79
- }, !headed);
80
- // Summary
106
+ }, !args.headed);
81
107
  const passed = reports.filter((r) => r.status === "passed").length;
82
108
  const failed = reports.filter((r) => r.status === "failed").length;
83
109
  const blocked = reports.filter((r) => r.status === "blocked").length;
@@ -88,7 +114,6 @@ async function main() {
88
114
  console.log(` \x1b[32m${passed} passed\x1b[0m \x1b[31m${failed} failed\x1b[0m ${blocked} blocked`);
89
115
  console.log(` Total time: ${(totalMs / 1000).toFixed(1)}s`);
90
116
  console.log("");
91
- // Report back
92
117
  log("Reporting results to Specwise...");
93
118
  try {
94
119
  await client.report(reports);
@@ -98,7 +123,6 @@ async function main() {
98
123
  log(`\x1b[31mFailed to report results: ${err instanceof Error ? err.message : err}\x1b[0m`);
99
124
  process.exit(1);
100
125
  }
101
- // Exit with error code if any failed
102
126
  process.exit(failed > 0 ? 1 : 0);
103
127
  }
104
128
  main().catch((err) => {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Discovery mode — opens a headed browser, lets user navigate,
3
+ * captures page elements and user actions in real time.
4
+ */
5
+ import type { SpecwiseAPI } from "./api.js";
6
+ export declare function runDiscovery(api: SpecwiseAPI, projectId: string, startUrl: string): Promise<void>;
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Discovery mode — opens a headed browser, lets user navigate,
3
+ * captures page elements and user actions in real time.
4
+ */
5
+ import { chromium } from "playwright";
6
+ import { log } from "./log.js";
7
+ const EXTRACT_ELEMENTS_JS = `() => {
8
+ const results = [];
9
+ const selectors = 'a, button, input, select, textarea, [role="button"], [role="link"], [role="tab"], [onclick], [data-testid], [type="submit"]';
10
+ const elements = document.querySelectorAll(selectors);
11
+
12
+ for (const el of elements) {
13
+ if (!el.offsetParent && el.tagName !== 'INPUT' && el.tagName !== 'SELECT') continue;
14
+
15
+ const tag = el.tagName.toLowerCase();
16
+ const inputType = el.getAttribute('type') || '';
17
+ const id = el.id || '';
18
+ const name = el.getAttribute('name') || '';
19
+ const testId = el.getAttribute('data-testid') || '';
20
+ const ariaLabel = el.getAttribute('aria-label') || '';
21
+
22
+ let elementType = 'other';
23
+ if (tag === 'input') {
24
+ const t = inputType.toLowerCase();
25
+ if (t === 'checkbox') elementType = 'checkbox';
26
+ else if (t === 'radio') elementType = 'radio';
27
+ else if (t === 'file') elementType = 'file';
28
+ else if (t === 'submit' || t === 'button') elementType = 'button';
29
+ else elementType = 'input';
30
+ } else if (tag === 'button' || el.getAttribute('role') === 'button') {
31
+ elementType = 'button';
32
+ } else if (tag === 'a' || el.getAttribute('role') === 'link') {
33
+ elementType = 'link';
34
+ } else if (tag === 'select') {
35
+ elementType = 'select';
36
+ } else if (tag === 'textarea') {
37
+ elementType = 'textarea';
38
+ }
39
+
40
+ let css = tag;
41
+ if (id) css = '#' + id;
42
+ else if (testId) css = '[data-testid="' + testId + '"]';
43
+ else if (name) css = tag + '[name="' + name + '"]';
44
+ else if (ariaLabel) css = tag + '[aria-label="' + ariaLabel + '"]';
45
+ else if (inputType) css = tag + '[type="' + inputType + '"]';
46
+
47
+ let xpath = '';
48
+ if (id) xpath = '//*[@id="' + id + '"]';
49
+ else if (name) xpath = '//' + tag + '[@name="' + name + '"]';
50
+ else if (testId) xpath = '//*[@data-testid="' + testId + '"]';
51
+
52
+ let formGroup = '';
53
+ const form = el.closest('form');
54
+ if (form) formGroup = form.id || form.getAttribute('name') || form.getAttribute('action') || 'form';
55
+
56
+ const options = [];
57
+ if (tag === 'select') {
58
+ for (const opt of el.options) {
59
+ if (opt.value) options.push(opt.value);
60
+ }
61
+ }
62
+
63
+ results.push({
64
+ tag,
65
+ element_type: elementType,
66
+ input_type: inputType,
67
+ id,
68
+ name,
69
+ css_selector: css,
70
+ xpath,
71
+ text: (el.textContent || '').trim().slice(0, 80),
72
+ placeholder: el.getAttribute('placeholder') || '',
73
+ aria_label: ariaLabel,
74
+ data_testid: testId,
75
+ role: el.getAttribute('role') || '',
76
+ href: tag === 'a' ? (el.getAttribute('href') || '').slice(0, 200) : '',
77
+ options: options.slice(0, 10),
78
+ is_required: el.required || el.getAttribute('aria-required') === 'true',
79
+ form_group: formGroup,
80
+ });
81
+ }
82
+ return results.slice(0, 100);
83
+ }`;
84
+ const EXTRACT_LINKS_JS = `() => {
85
+ const links = new Set();
86
+ for (const a of document.querySelectorAll('a[href]')) {
87
+ const href = a.href;
88
+ if (href && href.startsWith('http') && !href.includes('javascript:')) {
89
+ links.add(href.split('#')[0].split('?')[0]);
90
+ }
91
+ }
92
+ return [...links];
93
+ }`;
94
+ export async function runDiscovery(api, projectId, startUrl) {
95
+ log("Starting discovery mode...");
96
+ log("A browser will open. Navigate your app — each page's elements will be captured.");
97
+ log("Press Ctrl+C when you're done.\n");
98
+ const browser = await chromium.launch({ headless: false });
99
+ const context = await browser.newContext({ viewport: { width: 1280, height: 720 } });
100
+ const page = await context.newPage();
101
+ const capturedUrls = new Set();
102
+ const recordedActions = [];
103
+ let pagesCaptured = 0;
104
+ // Capture elements on every navigation
105
+ async function capturePage(p) {
106
+ const url = p.url();
107
+ if (url === "about:blank" || capturedUrls.has(url))
108
+ return;
109
+ try {
110
+ // Wait for SPA to fully render — network idle + DOM has interactive elements
111
+ await p.waitForLoadState("networkidle", { timeout: 15000 }).catch(() => { });
112
+ await p.waitForTimeout(2000); // extra buffer for JS frameworks to render
113
+ // Wait until at least one interactive element exists (SPA content loaded)
114
+ await p.waitForSelector("input, button, a[href], select, textarea, [role='button']", { timeout: 10000 }).catch(() => { });
115
+ // Retry element extraction — some SPAs render in multiple passes
116
+ let elements = [];
117
+ for (let attempt = 0; attempt < 3; attempt++) {
118
+ elements = await p.evaluate(EXTRACT_ELEMENTS_JS);
119
+ if (elements.length > 0)
120
+ break;
121
+ await p.waitForTimeout(1500);
122
+ }
123
+ const links = await p.evaluate(EXTRACT_LINKS_JS);
124
+ const title = await p.title();
125
+ await api.submitPage(projectId, {
126
+ url,
127
+ title,
128
+ elements,
129
+ links,
130
+ });
131
+ capturedUrls.add(url);
132
+ pagesCaptured++;
133
+ log(` Captured: ${title || url} (${elements.length} elements)`);
134
+ }
135
+ catch (err) {
136
+ // Page might have navigated away already
137
+ }
138
+ }
139
+ // Record user actions via CDP
140
+ const client = await context.newCDPSession(page);
141
+ // Track navigations
142
+ page.on("framenavigated", async (frame) => {
143
+ if (frame === page.mainFrame()) {
144
+ const url = frame.url();
145
+ recordedActions.push({
146
+ action: "navigate",
147
+ url,
148
+ page_title: await page.title().catch(() => ""),
149
+ selector: "",
150
+ xpath: "",
151
+ text: "",
152
+ value: "",
153
+ element_tag: "",
154
+ element_type: "",
155
+ element_name: "",
156
+ timestamp: new Date().toISOString(),
157
+ });
158
+ await capturePage(page);
159
+ }
160
+ });
161
+ // Inject action recorder into every page
162
+ await context.addInitScript(() => {
163
+ // Record clicks
164
+ document.addEventListener("click", (e) => {
165
+ const el = e.target?.closest("a, button, [role='button'], input[type='submit']");
166
+ if (!el)
167
+ return;
168
+ const data = {
169
+ action: "click",
170
+ selector: buildSel(el),
171
+ text: (el.textContent || "").trim().slice(0, 80),
172
+ element_tag: el.tagName.toLowerCase(),
173
+ };
174
+ window.__specwise_actions = window.__specwise_actions || [];
175
+ window.__specwise_actions.push(data);
176
+ }, true);
177
+ // Record input changes
178
+ document.addEventListener("change", (e) => {
179
+ const el = e.target;
180
+ if (!el || !["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName))
181
+ return;
182
+ const action = el.tagName === "SELECT" ? "select" : el.type === "checkbox" || el.type === "radio" ? "check" : "fill";
183
+ const data = {
184
+ action,
185
+ selector: buildSel(el),
186
+ value: el.value,
187
+ element_tag: el.tagName.toLowerCase(),
188
+ element_type: el.type || "",
189
+ element_name: el.name || "",
190
+ };
191
+ window.__specwise_actions = window.__specwise_actions || [];
192
+ window.__specwise_actions.push(data);
193
+ }, true);
194
+ function buildSel(el) {
195
+ if (el.id)
196
+ return "#" + el.id;
197
+ const testId = el.getAttribute("data-testid");
198
+ if (testId)
199
+ return `[data-testid="${testId}"]`;
200
+ const name = el.getAttribute("name");
201
+ if (name)
202
+ return `${el.tagName.toLowerCase()}[name="${name}"]`;
203
+ return el.tagName.toLowerCase();
204
+ }
205
+ });
206
+ // Poll for recorded actions from the page
207
+ const actionPollInterval = setInterval(async () => {
208
+ try {
209
+ const actions = await page.evaluate(() => {
210
+ const acts = window.__specwise_actions || [];
211
+ window.__specwise_actions = [];
212
+ return acts;
213
+ });
214
+ for (const act of actions) {
215
+ recordedActions.push({
216
+ ...act,
217
+ url: page.url(),
218
+ page_title: await page.title().catch(() => ""),
219
+ xpath: "",
220
+ timestamp: new Date().toISOString(),
221
+ });
222
+ }
223
+ }
224
+ catch {
225
+ // page might be navigating
226
+ }
227
+ }, 1000);
228
+ // Navigate to start URL
229
+ if (startUrl) {
230
+ await page.goto(startUrl, { waitUntil: "domcontentloaded", timeout: 15000 });
231
+ }
232
+ await capturePage(page);
233
+ // Wait for user to close browser or Ctrl+C
234
+ log("\nBrowse your app now. Each page will be captured automatically.");
235
+ log("Close the browser window or press Ctrl+C when done.\n");
236
+ await new Promise((resolve) => {
237
+ browser.on("disconnected", () => resolve());
238
+ process.on("SIGINT", async () => {
239
+ log("\nStopping discovery...");
240
+ clearInterval(actionPollInterval);
241
+ await browser.close().catch(() => { });
242
+ resolve();
243
+ });
244
+ });
245
+ clearInterval(actionPollInterval);
246
+ // Submit recorded flow
247
+ if (recordedActions.length > 0) {
248
+ log(`\nSaving recorded flow (${recordedActions.length} actions)...`);
249
+ try {
250
+ await api.submitFlow(projectId, {
251
+ steps: recordedActions,
252
+ start_url: startUrl || recordedActions[0]?.url || "",
253
+ });
254
+ log("\x1b[32mFlow saved!\x1b[0m");
255
+ }
256
+ catch (err) {
257
+ log(`\x1b[31mFailed to save flow: ${err instanceof Error ? err.message : err}\x1b[0m`);
258
+ }
259
+ }
260
+ console.log("");
261
+ console.log(" ─────────────────────────");
262
+ console.log(` \x1b[1mDiscovery complete\x1b[0m`);
263
+ console.log(` \x1b[32m${pagesCaptured} pages captured\x1b[0m`);
264
+ console.log(` ${recordedActions.length} actions recorded`);
265
+ console.log("");
266
+ }
267
+ //# sourceMappingURL=discoverer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discoverer.js","sourceRoot":"","sources":["../src/discoverer.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { SpecwiseAPI } from "./api.js";
2
2
  export { executeTestRun } from "./runner.js";
3
3
  export { recordPipeline } from "./recorder.js";
4
+ export { runDiscovery } from "./discoverer.js";
4
5
  export type * from "./types.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { SpecwiseAPI } from "./api.js";
2
2
  export { executeTestRun } from "./runner.js";
3
3
  export { recordPipeline } from "./recorder.js";
4
+ export { runDiscovery } from "./discoverer.js";
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specwise/runner",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Local test runner for Specwise — executes test cases on your machine with Playwright",
5
5
  "type": "module",
6
6
  "bin": {