cstesting 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # CSTesting
2
+
3
+ A simple, extensible **Node.js testing framework**. Start with a test runner and assertions (like a minimal Jest/Mocha), plus CDP-based browser automation (no Playwright/Cypress).
4
+
5
+ ## For end users — install and run
6
+
7
+ ```bash
8
+ # Install in your project
9
+ npm install cstesting
10
+
11
+ # Run tests (discovers *.test.js / *.spec.js)
12
+ npx cstesting
13
+ npx cstesting "**/*.test.js"
14
+ npx cst
15
+ ```
16
+
17
+ Use in code: `const { describe, it, expect, createBrowser } = require('cstesting');`
18
+
19
+ ## Quick Start
20
+
21
+ 1. **Create a test file** (e.g. `math.test.js`):
22
+
23
+ ```js
24
+ const { describe, it, expect } = require('cstesting');
25
+
26
+ describe('Math', () => {
27
+ it('adds numbers', () => {
28
+ expect(1 + 1).toBe(2);
29
+ });
30
+
31
+ it('compares objects', () => {
32
+ expect({ a: 1 }).toEqual({ a: 1 });
33
+ });
34
+ });
35
+ ```
36
+
37
+ 2. **Run tests**:
38
+
39
+ ```bash
40
+ npx cstesting
41
+ # or
42
+ npx cstesting "**/*.test.js"
43
+ npx cstesting tests/
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### Test structure
49
+
50
+ - **`describe(name, fn)`** — define a suite (nested suites supported)
51
+ - **`it(name, fn)`** — define a test (async supported)
52
+ - **`describe.only` / `it.only`** — run only this suite/test
53
+ - **`describe.skip` / `it.skip`** — skip this suite/test
54
+
55
+ ### Hooks
56
+
57
+ - **`beforeAll(fn)`** — run once before all tests in the suite
58
+ - **`afterAll(fn)`** — run once after all tests in the suite
59
+ - **`beforeEach(fn)`** — run before each test
60
+ - **`afterEach(fn)`** — run after each test
61
+
62
+ ### Assertions (`expect(value)`)
63
+
64
+ | Matcher | Example |
65
+ |--------|--------|
66
+ | `toBe(expected)` | strict equality (`Object.is`) |
67
+ | `toEqual(expected)` | deep equality (JSON) |
68
+ | `toBeTruthy()` / `toBeFalsy()` | boolean check |
69
+ | `toBeNull()` / `toBeDefined()` / `toBeUndefined()` | null/undefined |
70
+ | `toThrow(message?)` | expect(fn).toThrow() |
71
+ | `toBeGreaterThan(n)` / `toBeLessThan(n)` | numbers |
72
+ | `toContain(item)` | arrays and strings |
73
+ | `toHaveLength(n)` | length |
74
+ | `expect(x).not.toBe(y)` | negate any matcher |
75
+
76
+ ## Programmatic usage
77
+
78
+ ```js
79
+ const { describe, it, expect, run } = require('cstesting');
80
+
81
+ describe('My tests', () => {
82
+ it('works', () => {
83
+ expect(1).toBe(1);
84
+ });
85
+ });
86
+
87
+ run().then((result) => {
88
+ console.log(result); // { passed, failed, skipped, total, duration, errors }
89
+ });
90
+ ```
91
+
92
+ ## Browser automation (no Playwright/Cypress)
93
+
94
+ EasyTesting includes a **CDP-based** browser API using the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) via `chrome-remote-interface` and `chrome-launcher`. No Playwright or Cypress — just Chrome (or Chromium) and Node.
95
+
96
+ **Requirements:** Chrome or Chromium installed (the same binary Puppeteer uses; `chrome-launcher` finds it).
97
+
98
+ ```js
99
+ const { createBrowser, describe, it, expect, beforeAll, afterAll } = require('cstesting');
100
+
101
+ describe('My site', () => {
102
+ let browser;
103
+
104
+ beforeAll(async () => {
105
+ browser = await createBrowser({ headless: true });
106
+ });
107
+
108
+ afterAll(async () => {
109
+ await browser.close();
110
+ });
111
+
112
+ it('loads the page', async () => {
113
+ await browser.goto('https://example.com');
114
+ const html = await browser.content();
115
+ expect(html).toContain('Example Domain');
116
+ });
117
+
118
+ it('clicks and types', async () => {
119
+ await browser.goto('https://example.com');
120
+ await browser.click('a'); // click first link
121
+ await browser.type('input', 'hi'); // type into first input
122
+ });
123
+ });
124
+ ```
125
+
126
+ ### Browser API
127
+
128
+ | Method | Description |
129
+ |--------|-------------|
130
+ | `createBrowser(options?)` | Launch Chrome (or connect to existing `port`). Returns a browser object. |
131
+ | `browser.goto(url)` | Navigate to URL (waits for load). |
132
+ | `browser.click(selector)` | Click element matching CSS `selector`. |
133
+ | `browser.type(selector, text)` | Focus and type into element. |
134
+ | `browser.pressKey(key)` | Press a key (e.g. `'Enter'`). |
135
+ | `browser.waitForLoad()` | Wait for the next page load (e.g. after form submit). |
136
+ | `browser.content()` | Return page HTML. |
137
+ | `browser.evaluate(expression)` | Run JS in the page and return the value. |
138
+ | `browser.close()` | Close the browser. |
139
+
140
+ **Options for `createBrowser({ ... })`:**
141
+
142
+ - `headless` (default: `true`) — run without a visible window
143
+ - `port` — use an existing Chrome with `--remote-debugging-port=9222` instead of launching
144
+ - `args` — extra Chrome flags (e.g. `['--disable-web-security']`)
145
+ - `userDataDir` — custom Chrome profile path (avoids Windows EPERM on default temp folder)
146
+
147
+ **Windows EPERM / Permission denied:** If you see `EPERM, Permission denied` on a `lighthouse.xxxxx` temp path, the launcher now uses a custom profile dir under your project (`node_modules/.cache/`) or `os.tmpdir()` instead of the default. You can also set `userDataDir` to a path you control, e.g. `createBrowser({ userDataDir: 'C:\\MyChromeProfile' })`.
148
+
149
+ ## Roadmap (improve after publish)
150
+
151
+ 1. **Browser automation** — Done. CDP-based `browser.goto()`, `click()`, `type()` (no Playwright/Cypress).
152
+ 2. **DOM / jsdom** — Add optional `cstesting-dom` for testing DOM in Node without a browser.
153
+ 3. **More browser APIs** — `waitForSelector`, screenshots, multiple tabs.
154
+ 4. **Reporters** — JSON, JUnit XML, HTML report for CI and dashboards.
155
+ 5. **Watch mode** — Re-run tests on file changes.
156
+ 6. **Coverage** — Optional integration with Istanbul/c8.
157
+ 7. **More matchers** — `toMatchObject`, `toMatch(regex)`, `resolves`/`rejects` for promises.
158
+ 8. **Timeouts** — Per-test and global timeouts.
159
+ 9. **Parallel runs** — Run test files in parallel (with care for shared resources).
160
+
161
+ ## Development
162
+
163
+ From the repo root:
164
+
165
+ ```bash
166
+ npm install
167
+ npm run build
168
+ npm install . # install this package into node_modules so example can require('cstesting')
169
+ npm run test:example # run example tests
170
+ ```
171
+
172
+ ## License
173
+
174
+ MIT
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Simple assertion library (expect-style API).
3
+ * Similar to Jest/Cypress expect — extend later with matchers.
4
+ */
5
+ export declare class AssertionError extends Error {
6
+ readonly expected?: unknown | undefined;
7
+ readonly actual?: unknown | undefined;
8
+ constructor(message: string, expected?: unknown | undefined, actual?: unknown | undefined);
9
+ }
10
+ export interface ExpectApi {
11
+ toBe(expected: unknown): void;
12
+ toEqual(expected: unknown): void;
13
+ toBeTruthy(): void;
14
+ toBeFalsy(): void;
15
+ toBeNull(): void;
16
+ toBeDefined(): void;
17
+ toBeUndefined(): void;
18
+ toThrow(expectedMessage?: string | RegExp): void;
19
+ toBeGreaterThan(n: number): void;
20
+ toBeLessThan(n: number): void;
21
+ toContain(item: unknown): void;
22
+ toHaveLength(n: number): void;
23
+ not: ExpectApi;
24
+ }
25
+ /**
26
+ * Expect API — use in tests: expect(value).toBe(3), expect(fn).toThrow(), etc.
27
+ */
28
+ export declare function expect(actual: unknown): ExpectApi;
29
+ //# sourceMappingURL=assertions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../src/assertions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,cAAe,SAAQ,KAAK;aAGrB,QAAQ,CAAC,EAAE,OAAO;aAClB,MAAM,CAAC,EAAE,OAAO;gBAFhC,OAAO,EAAE,MAAM,EACC,QAAQ,CAAC,EAAE,OAAO,YAAA,EAClB,MAAM,CAAC,EAAE,OAAO,YAAA;CAMnC;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,UAAU,IAAI,IAAI,CAAC;IACnB,SAAS,IAAI,IAAI,CAAC;IAClB,QAAQ,IAAI,IAAI,CAAC;IACjB,WAAW,IAAI,IAAI,CAAC;IACpB,aAAa,IAAI,IAAI,CAAC;IACtB,OAAO,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACjD,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,GAAG,EAAE,SAAS,CAAC;CAChB;AAyGD;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAEjD"}
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ /**
3
+ * Simple assertion library (expect-style API).
4
+ * Similar to Jest/Cypress expect — extend later with matchers.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.AssertionError = void 0;
8
+ exports.expect = expect;
9
+ class AssertionError extends Error {
10
+ constructor(message, expected, actual) {
11
+ super(message);
12
+ this.expected = expected;
13
+ this.actual = actual;
14
+ this.name = 'AssertionError';
15
+ Object.setPrototypeOf(this, AssertionError.prototype);
16
+ }
17
+ }
18
+ exports.AssertionError = AssertionError;
19
+ function assert(condition, message, actual, expected) {
20
+ if (!condition) {
21
+ throw new AssertionError(message, expected, actual);
22
+ }
23
+ }
24
+ function expectApi(actual, negate = false) {
25
+ const wrap = (pass, failMessage, passMessage) => {
26
+ const ok = negate ? !pass : pass;
27
+ const msg = ok ? (negate ? failMessage : passMessage || failMessage) : (negate ? passMessage || failMessage : failMessage);
28
+ assert(ok, msg, actual);
29
+ };
30
+ const api = {
31
+ toBe(expected) {
32
+ wrap(Object.is(actual, expected), `Expected ${String(actual)} to be ${String(expected)}`, `Expected not to be ${String(expected)}`);
33
+ },
34
+ toEqual(expected) {
35
+ const pass = JSON.stringify(actual) === JSON.stringify(expected);
36
+ wrap(pass, `Expected ${JSON.stringify(actual)} to equal ${JSON.stringify(expected)}`, `Expected not to equal ${JSON.stringify(expected)}`);
37
+ },
38
+ toBeTruthy() {
39
+ wrap(!!actual, `Expected ${String(actual)} to be truthy`, `Expected ${String(actual)} to be falsy`);
40
+ },
41
+ toBeFalsy() {
42
+ wrap(!actual, `Expected ${String(actual)} to be falsy`, `Expected ${String(actual)} to be truthy`);
43
+ },
44
+ toBeNull() {
45
+ wrap(actual === null, `Expected ${String(actual)} to be null`, `Expected not to be null`);
46
+ },
47
+ toBeDefined() {
48
+ wrap(actual !== undefined, `Expected value to be defined`, `Expected value to be undefined`);
49
+ },
50
+ toBeUndefined() {
51
+ wrap(actual === undefined, `Expected value to be undefined`, `Expected value to be defined`);
52
+ },
53
+ toThrow(expectedMessage) {
54
+ if (typeof actual !== 'function') {
55
+ throw new AssertionError('Expected value to be a function', undefined, actual);
56
+ }
57
+ let threw = false;
58
+ let thrown;
59
+ try {
60
+ actual();
61
+ }
62
+ catch (e) {
63
+ threw = true;
64
+ thrown = e;
65
+ }
66
+ wrap(threw, 'Expected function to throw', 'Expected function not to throw');
67
+ if (expectedMessage !== undefined && threw) {
68
+ const msg = thrown instanceof Error ? thrown.message : String(thrown);
69
+ const match = typeof expectedMessage === 'string'
70
+ ? msg === expectedMessage
71
+ : expectedMessage.test(msg);
72
+ assert(match, `Expected throw message to match, got: ${msg}`, msg, expectedMessage);
73
+ }
74
+ },
75
+ toBeGreaterThan(n) {
76
+ const val = Number(actual);
77
+ wrap(!Number.isNaN(val) && val > n, `Expected ${actual} to be greater than ${n}`, `Expected ${actual} not to be greater than ${n}`);
78
+ },
79
+ toBeLessThan(n) {
80
+ const val = Number(actual);
81
+ wrap(!Number.isNaN(val) && val < n, `Expected ${actual} to be less than ${n}`, `Expected ${actual} not to be less than ${n}`);
82
+ },
83
+ toContain(item) {
84
+ const isArray = Array.isArray(actual);
85
+ const isString = typeof actual === 'string';
86
+ const has = isArray
87
+ ? actual.includes(item)
88
+ : isString
89
+ ? actual.includes(String(item))
90
+ : false;
91
+ wrap(has, `Expected ${JSON.stringify(actual)} to contain ${JSON.stringify(item)}`, `Expected ${JSON.stringify(actual)} not to contain ${JSON.stringify(item)}`);
92
+ },
93
+ toHaveLength(n) {
94
+ const len = actual?.length;
95
+ wrap(len === n, `Expected length ${len ?? 'undefined'} to be ${n}`, `Expected length not to be ${n}`);
96
+ },
97
+ get not() {
98
+ return expectApi(actual, true);
99
+ },
100
+ };
101
+ return api;
102
+ }
103
+ /**
104
+ * Expect API — use in tests: expect(value).toBe(3), expect(fn).toThrow(), etc.
105
+ */
106
+ function expect(actual) {
107
+ return expectApi(actual);
108
+ }
109
+ //# sourceMappingURL=assertions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.js","sourceRoot":"","sources":["../src/assertions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Page API: goto, click, type using Chrome DevTools Protocol only.
3
+ * No Playwright, no Cypress — raw CDP via chrome-remote-interface.
4
+ */
5
+ interface EvalResult {
6
+ result?: {
7
+ type: string;
8
+ value?: unknown;
9
+ };
10
+ }
11
+ export type CDPClient = {
12
+ Page: {
13
+ enable(): Promise<void>;
14
+ navigate(params: {
15
+ url: string;
16
+ }): Promise<unknown>;
17
+ loadEventFired(): Promise<unknown>;
18
+ };
19
+ Runtime: {
20
+ evaluate(params: {
21
+ expression: string;
22
+ returnByValue?: boolean;
23
+ }): Promise<EvalResult>;
24
+ };
25
+ Input: {
26
+ dispatchMouseEvent(params: {
27
+ type: string;
28
+ x: number;
29
+ y: number;
30
+ button?: string;
31
+ clickCount?: number;
32
+ }): Promise<void>;
33
+ dispatchKeyEvent(params: {
34
+ type: string;
35
+ text?: string;
36
+ key?: string;
37
+ }): Promise<void>;
38
+ };
39
+ close(): Promise<void>;
40
+ };
41
+ export interface PageApi {
42
+ goto(url: string): Promise<void>;
43
+ click(selector: string): Promise<void>;
44
+ type(selector: string, text: string): Promise<void>;
45
+ pressKey(key: string): Promise<void>;
46
+ waitForLoad(): Promise<void>;
47
+ content(): Promise<string>;
48
+ evaluate<T>(expression: string): Promise<T>;
49
+ }
50
+ export declare function createPage(client: CDPClient): PageApi;
51
+ export {};
52
+ //# sourceMappingURL=cdp-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-page.d.ts","sourceRoot":"","sources":["../../src/browser/cdp-page.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,UAAU;IAClB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC5C;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE;QAAE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAAC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC;IAC3H,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;KAAE,CAAC;IACpG,KAAK,EAAE;QAAE,kBAAkB,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,gBAAgB,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAC3N,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3B,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7C;AASD,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CA0ErD"}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ /**
3
+ * Page API: goto, click, type using Chrome DevTools Protocol only.
4
+ * No Playwright, no Cypress — raw CDP via chrome-remote-interface.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createPage = createPage;
8
+ function getCenter(rect) {
9
+ return {
10
+ x: rect.x + rect.width / 2,
11
+ y: rect.y + rect.height / 2,
12
+ };
13
+ }
14
+ function createPage(client) {
15
+ return {
16
+ async goto(url) {
17
+ await client.Page.enable();
18
+ await client.Page.navigate({ url });
19
+ await client.Page.loadEventFired();
20
+ },
21
+ async click(selector) {
22
+ const expr = `
23
+ (function() {
24
+ var el = document.querySelector(${JSON.stringify(selector)});
25
+ if (!el) throw new Error('No element found for selector: ${selector.replace(/'/g, "\\'")}');
26
+ var r = el.getBoundingClientRect();
27
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
28
+ })()
29
+ `;
30
+ const { result } = await client.Runtime.evaluate({ expression: expr, returnByValue: true });
31
+ if (!result || result.type !== 'object' || !('value' in result)) {
32
+ throw new Error(`Selector "${selector}" did not match or element has no box`);
33
+ }
34
+ const value = result.value;
35
+ const { x, y } = getCenter(value);
36
+ await client.Input.dispatchMouseEvent({ type: 'mousePressed', x, y, button: 'left', clickCount: 1 });
37
+ await client.Input.dispatchMouseEvent({ type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });
38
+ },
39
+ async type(selector, text) {
40
+ const expr = `
41
+ (function() {
42
+ var el = document.querySelector(${JSON.stringify(selector)});
43
+ if (!el) throw new Error('No element found for selector: ${selector.replace(/'/g, "\\'")}');
44
+ var r = el.getBoundingClientRect();
45
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
46
+ })()
47
+ `;
48
+ const { result } = await client.Runtime.evaluate({ expression: expr, returnByValue: true });
49
+ if (!result || result.type !== 'object' || !('value' in result)) {
50
+ throw new Error(`Selector "${selector}" did not match`);
51
+ }
52
+ const value = result.value;
53
+ const { x, y } = getCenter(value);
54
+ await client.Input.dispatchMouseEvent({ type: 'mousePressed', x, y, button: 'left', clickCount: 1 });
55
+ await client.Input.dispatchMouseEvent({ type: 'mouseReleased', x, y, button: 'left', clickCount: 1 });
56
+ for (const char of text) {
57
+ await client.Input.dispatchKeyEvent({ type: 'keyDown', text: char });
58
+ await client.Input.dispatchKeyEvent({ type: 'keyUp', text: char });
59
+ }
60
+ },
61
+ async pressKey(key) {
62
+ await client.Input.dispatchKeyEvent({ type: 'keyDown', key });
63
+ await client.Input.dispatchKeyEvent({ type: 'keyUp', key });
64
+ },
65
+ async waitForLoad() {
66
+ await client.Page.loadEventFired();
67
+ },
68
+ async content() {
69
+ const { result } = await client.Runtime.evaluate({
70
+ expression: 'document.documentElement.outerHTML',
71
+ returnByValue: true,
72
+ });
73
+ if (result && 'value' in result)
74
+ return String(result.value);
75
+ return '';
76
+ },
77
+ async evaluate(expression) {
78
+ const { result } = await client.Runtime.evaluate({ expression, returnByValue: true });
79
+ if (result && 'value' in result)
80
+ return result.value;
81
+ return undefined;
82
+ },
83
+ };
84
+ }
85
+ //# sourceMappingURL=cdp-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-page.js","sourceRoot":"","sources":["../../src/browser/cdp-page.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * CSTesting Browser — CDP-based automation (no Playwright/Cypress).
3
+ * Uses Chrome DevTools Protocol via chrome-remote-interface + chrome-launcher.
4
+ */
5
+ import { type LaunchOptions } from './launch';
6
+ export interface BrowserApi {
7
+ goto(url: string): Promise<void>;
8
+ click(selector: string): Promise<void>;
9
+ type(selector: string, text: string): Promise<void>;
10
+ pressKey(key: string): Promise<void>;
11
+ waitForLoad(): Promise<void>;
12
+ content(): Promise<string>;
13
+ evaluate<T>(expression: string): Promise<T>;
14
+ close(): Promise<void>;
15
+ }
16
+ export interface CreateBrowserOptions extends LaunchOptions {
17
+ /** Connect to existing Chrome on port instead of launching. */
18
+ port?: number;
19
+ }
20
+ /**
21
+ * Launch a new Chrome (or connect to existing port) and return a browser API.
22
+ * Example:
23
+ * const browser = await createBrowser({ headless: true });
24
+ * await browser.goto('https://example.com');
25
+ * await browser.click('a');
26
+ * await browser.close();
27
+ */
28
+ export declare function createBrowser(options?: CreateBrowserOptions): Promise<BrowserApi>;
29
+ export { launchChrome } from './launch';
30
+ export type { PageApi } from './cdp-page';
31
+ export type { LaunchOptions, LaunchedChrome } from './launch';
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAgB,KAAK,aAAa,EAAuB,MAAM,UAAU,CAAC;AAIjF,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3B,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiC3F;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ /**
3
+ * CSTesting Browser — CDP-based automation (no Playwright/Cypress).
4
+ * Uses Chrome DevTools Protocol via chrome-remote-interface + chrome-launcher.
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.launchChrome = void 0;
11
+ exports.createBrowser = createBrowser;
12
+ const chrome_remote_interface_1 = __importDefault(require("chrome-remote-interface"));
13
+ const launch_1 = require("./launch");
14
+ const cdp_page_1 = require("./cdp-page");
15
+ /**
16
+ * Launch a new Chrome (or connect to existing port) and return a browser API.
17
+ * Example:
18
+ * const browser = await createBrowser({ headless: true });
19
+ * await browser.goto('https://example.com');
20
+ * await browser.click('a');
21
+ * await browser.close();
22
+ */
23
+ async function createBrowser(options = {}) {
24
+ let launched = null;
25
+ let port = options.port;
26
+ if (port == null || port === 0) {
27
+ launched = await (0, launch_1.launchChrome)({
28
+ headless: options.headless,
29
+ port: options.port,
30
+ args: options.args,
31
+ userDataDir: options.userDataDir,
32
+ });
33
+ port = launched.port;
34
+ }
35
+ const client = (await (0, chrome_remote_interface_1.default)({ port }));
36
+ const page = (0, cdp_page_1.createPage)(client);
37
+ return {
38
+ goto: (url) => page.goto(url),
39
+ click: (selector) => page.click(selector),
40
+ type: (selector, text) => page.type(selector, text),
41
+ pressKey: (key) => page.pressKey(key),
42
+ waitForLoad: () => page.waitForLoad(),
43
+ content: () => page.content(),
44
+ evaluate: (expression) => page.evaluate(expression),
45
+ async close() {
46
+ await client.close();
47
+ if (launched) {
48
+ const k = launched.kill();
49
+ if (k && typeof k.then === 'function')
50
+ await k;
51
+ }
52
+ },
53
+ };
54
+ }
55
+ var launch_2 = require("./launch");
56
+ Object.defineProperty(exports, "launchChrome", { enumerable: true, get: function () { return launch_2.launchChrome; } });
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AA+BH,sCAiCC;AA9DD,sFAA0C;AAC1C,qCAAiF;AACjF,yCAAsD;AAmBtD;;;;;;;GAOG;AACI,KAAK,UAAU,aAAa,CAAC,UAAgC,EAAE;IACpE,IAAI,QAAQ,GAA0B,IAAI,CAAC;IAC3C,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAExB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QAC/B,QAAQ,GAAG,MAAM,IAAA,qBAAY,EAAC;YAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC,CAAC;QACH,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,MAAM,IAAA,iCAAG,EAAC,EAAE,IAAI,EAAE,CAAC,CAAyB,CAAC;IAC7D,MAAM,IAAI,GAAG,IAAA,qBAAU,EAAC,MAAM,CAAC,CAAC;IAEhC,OAAO;QACL,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACrC,KAAK,EAAE,CAAC,QAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;QACjD,IAAI,EAAE,CAAC,QAAgB,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;QACnE,QAAQ,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC7C,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE;QACrC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;QAC7B,QAAQ,EAAE,CAAI,UAAkB,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAI,UAAU,CAAC;QACjE,KAAK,CAAC,KAAK;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC1B,IAAI,CAAC,IAAI,OAAQ,CAAsB,CAAC,IAAI,KAAK,UAAU;oBAAE,MAAO,CAAmB,CAAC;YAC1F,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,mCAAwC;AAA/B,sGAAA,YAAY,OAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Launch Chrome with remote-debugging-port for CDP.
3
+ * Uses chrome-launcher (no Playwright/Puppeteer).
4
+ * Uses a custom userDataDir to avoid Windows EPERM on the default lighthouse temp folder.
5
+ */
6
+ export interface LaunchOptions {
7
+ headless?: boolean;
8
+ port?: number;
9
+ args?: string[];
10
+ /** Custom Chrome profile directory. If not set, a dir under project or os.tmpdir() is used to avoid Windows EPERM. */
11
+ userDataDir?: string;
12
+ }
13
+ export interface LaunchedChrome {
14
+ port: number;
15
+ kill: () => void | Promise<void>;
16
+ }
17
+ export declare function launchChrome(options?: LaunchOptions): Promise<LaunchedChrome>;
18
+ //# sourceMappingURL=launch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/browser/launch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,sHAAsH;IACtH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAgBD,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyBvF"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * Launch Chrome with remote-debugging-port for CDP.
4
+ * Uses chrome-launcher (no Playwright/Puppeteer).
5
+ * Uses a custom userDataDir to avoid Windows EPERM on the default lighthouse temp folder.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.launchChrome = launchChrome;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const os = __importStar(require("os"));
45
+ const chrome_launcher_1 = require("chrome-launcher");
46
+ function makeUserDataDir() {
47
+ const base = process.cwd();
48
+ const dirName = `cstesting-chrome-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
49
+ const candidate = path.join(base, 'node_modules', '.cache', dirName);
50
+ try {
51
+ fs.mkdirSync(candidate, { recursive: true });
52
+ return path.resolve(candidate);
53
+ }
54
+ catch {
55
+ const fallback = path.join(os.tmpdir(), dirName);
56
+ fs.mkdirSync(fallback, { recursive: true });
57
+ return path.resolve(fallback);
58
+ }
59
+ }
60
+ async function launchChrome(options = {}) {
61
+ const { headless = true, port = 0, args = [], userDataDir: customUserDataDir } = options;
62
+ const chromeFlags = [...args];
63
+ if (headless) {
64
+ chromeFlags.push('--headless=new', '--disable-gpu', '--no-sandbox');
65
+ }
66
+ const userDataDir = customUserDataDir ?? makeUserDataDir();
67
+ const chrome = await (0, chrome_launcher_1.launch)({
68
+ port: port || undefined,
69
+ chromeFlags,
70
+ userDataDir,
71
+ });
72
+ return {
73
+ port: chrome.port,
74
+ kill: () => {
75
+ chrome.kill();
76
+ try {
77
+ if (!customUserDataDir && fs.existsSync(userDataDir)) {
78
+ fs.rmSync(userDataDir, { recursive: true, force: true, maxRetries: 3 });
79
+ }
80
+ }
81
+ catch {
82
+ // ignore cleanup errors
83
+ }
84
+ },
85
+ };
86
+ }
87
+ //# sourceMappingURL=launch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch.js","sourceRoot":"","sources":["../../src/browser/launch.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCH,oCAyBC;AAzDD,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AACzB,qDAA+D;AAe/D,SAAS,eAAe;IACtB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,oBAAoB,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAC5F,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;QACjD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,UAAyB,EAAE;IAC5D,MAAM,EAAE,QAAQ,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,EAAE,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;IACzF,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IAC9B,IAAI,QAAQ,EAAE,CAAC;QACb,WAAW,CAAC,IAAI,CAAC,gBAAgB,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,WAAW,GAAG,iBAAiB,IAAI,eAAe,EAAE,CAAC;IAC3D,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAkB,EAAC;QACtC,IAAI,EAAE,IAAI,IAAI,SAAS;QACvB,WAAW;QACX,WAAW;KACZ,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,GAAG,EAAE;YACT,MAAM,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;oBACrD,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC1E,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // CSTesting CLI — discover and run test files.
4
+ // Usage: npx cstesting [pattern] or npx et [pattern]
5
+ // Examples: cstesting | cstesting "**/*.test.js" | cstesting tests/
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const path = __importStar(require("path"));
41
+ const fs = __importStar(require("fs"));
42
+ const runner_1 = require("./runner");
43
+ const assertions_1 = require("./assertions");
44
+ const defaultPattern = '**/*.test.js';
45
+ function findTestFiles(pattern, cwd) {
46
+ const base = pattern.split(/[/\\]/)[0];
47
+ if (base === '**' || pattern.includes('*')) {
48
+ const files = [];
49
+ function walk(dir) {
50
+ if (!fs.existsSync(dir))
51
+ return;
52
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
53
+ for (const e of entries) {
54
+ const full = path.join(dir, e.name);
55
+ if (e.isDirectory()) {
56
+ if (e.name !== 'node_modules' && e.name !== 'dist')
57
+ walk(full);
58
+ }
59
+ else if (e.isFile() && (e.name.endsWith('.test.js') || e.name.endsWith('.spec.js'))) {
60
+ files.push(full);
61
+ }
62
+ }
63
+ }
64
+ walk(cwd);
65
+ return files;
66
+ }
67
+ const full = path.join(cwd, pattern);
68
+ if (fs.existsSync(full) && fs.statSync(full).isFile())
69
+ return [path.resolve(full)];
70
+ const dir = path.join(cwd, base);
71
+ if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
72
+ const files = [];
73
+ function walk(d) {
74
+ const entries = fs.readdirSync(d, { withFileTypes: true });
75
+ for (const e of entries) {
76
+ const fullPath = path.join(d, e.name);
77
+ if (e.isDirectory())
78
+ walk(fullPath);
79
+ else if (e.name.endsWith('.test.js') || e.name.endsWith('.spec.js'))
80
+ files.push(fullPath);
81
+ }
82
+ }
83
+ walk(dir);
84
+ return files;
85
+ }
86
+ return [];
87
+ }
88
+ function loadTestFile(filePath) {
89
+ require(path.resolve(filePath));
90
+ }
91
+ function formatError(err) {
92
+ if (err instanceof assertions_1.AssertionError) {
93
+ return `${err.message}${err.actual !== undefined ? `\n Actual: ${String(err.actual)}` : ''}${err.expected !== undefined ? `\n Expected: ${String(err.expected)}` : ''}`;
94
+ }
95
+ return err.stack || err.message;
96
+ }
97
+ async function main() {
98
+ const cwd = process.cwd();
99
+ const pattern = process.argv[2] || defaultPattern;
100
+ const resolved = path.resolve(cwd, pattern);
101
+ let testFiles;
102
+ if (pattern.includes('*') || pattern.endsWith('.js') || pattern.endsWith('.ts')) {
103
+ testFiles = findTestFiles(pattern, cwd);
104
+ }
105
+ else if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
106
+ testFiles = findTestFiles(pattern, cwd);
107
+ }
108
+ else if (fs.existsSync(resolved) && fs.statSync(resolved).isFile()) {
109
+ testFiles = [resolved];
110
+ }
111
+ else {
112
+ testFiles = findTestFiles(pattern, cwd);
113
+ }
114
+ if (testFiles.length === 0) {
115
+ console.log('No test files found. Create files matching *.test.js or run: cstesting path/to/test.js');
116
+ process.exit(0);
117
+ return;
118
+ }
119
+ const totalResult = {
120
+ passed: 0,
121
+ failed: 0,
122
+ skipped: 0,
123
+ total: 0,
124
+ duration: 0,
125
+ errors: [],
126
+ };
127
+ for (const file of testFiles) {
128
+ (0, runner_1.resetRunner)();
129
+ try {
130
+ loadTestFile(file);
131
+ }
132
+ catch (err) {
133
+ console.error(`Failed to load ${file}:`, err);
134
+ process.exit(1);
135
+ }
136
+ const result = await (0, runner_1.run)();
137
+ totalResult.passed += result.passed;
138
+ totalResult.failed += result.failed;
139
+ totalResult.skipped += result.skipped;
140
+ totalResult.total += result.total;
141
+ totalResult.duration += result.duration;
142
+ totalResult.errors.push(...result.errors);
143
+ const rel = path.relative(cwd, file);
144
+ console.log(`\n ${rel}`);
145
+ if (result.errors.length > 0) {
146
+ for (const { suite, test, error } of result.errors) {
147
+ console.log(` ✗ ${suite} > ${test}`);
148
+ console.log(formatError(error).split('\n').map((l) => ` ${l}`).join('\n'));
149
+ }
150
+ }
151
+ }
152
+ console.log('\n' + '─'.repeat(50));
153
+ console.log(` Passed: ${totalResult.passed} Failed: ${totalResult.failed} Skipped: ${totalResult.skipped} Total: ${totalResult.total} (${totalResult.duration}ms)`);
154
+ if (totalResult.failed > 0)
155
+ process.exit(1);
156
+ }
157
+ main().catch((err) => {
158
+ console.error(err);
159
+ process.exit(1);
160
+ });
161
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CSTesting — Node.js testing framework
3
+ *
4
+ * Usage in test files:
5
+ * const { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } = require('cstesting');
6
+ */
7
+ export { describe, it, beforeAll, afterAll, beforeEach, afterEach, run, resetRunner } from './runner';
8
+ export { expect, AssertionError } from './assertions';
9
+ export { createBrowser } from './browser';
10
+ export type { RunResult } from './types';
11
+ export type { BrowserApi, CreateBrowserOptions } from './browser';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACtG,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * CSTesting — Node.js testing framework
4
+ *
5
+ * Usage in test files:
6
+ * const { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } = require('cstesting');
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.createBrowser = exports.AssertionError = exports.expect = exports.resetRunner = exports.run = exports.afterEach = exports.beforeEach = exports.afterAll = exports.beforeAll = exports.it = exports.describe = void 0;
10
+ var runner_1 = require("./runner");
11
+ Object.defineProperty(exports, "describe", { enumerable: true, get: function () { return runner_1.describe; } });
12
+ Object.defineProperty(exports, "it", { enumerable: true, get: function () { return runner_1.it; } });
13
+ Object.defineProperty(exports, "beforeAll", { enumerable: true, get: function () { return runner_1.beforeAll; } });
14
+ Object.defineProperty(exports, "afterAll", { enumerable: true, get: function () { return runner_1.afterAll; } });
15
+ Object.defineProperty(exports, "beforeEach", { enumerable: true, get: function () { return runner_1.beforeEach; } });
16
+ Object.defineProperty(exports, "afterEach", { enumerable: true, get: function () { return runner_1.afterEach; } });
17
+ Object.defineProperty(exports, "run", { enumerable: true, get: function () { return runner_1.run; } });
18
+ Object.defineProperty(exports, "resetRunner", { enumerable: true, get: function () { return runner_1.resetRunner; } });
19
+ var assertions_1 = require("./assertions");
20
+ Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return assertions_1.expect; } });
21
+ Object.defineProperty(exports, "AssertionError", { enumerable: true, get: function () { return assertions_1.AssertionError; } });
22
+ var browser_1 = require("./browser");
23
+ Object.defineProperty(exports, "createBrowser", { enumerable: true, get: function () { return browser_1.createBrowser; } });
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,mCAAsG;AAA7F,kGAAA,QAAQ,OAAA;AAAE,4FAAA,EAAE,OAAA;AAAE,mGAAA,SAAS,OAAA;AAAE,kGAAA,QAAQ,OAAA;AAAE,oGAAA,UAAU,OAAA;AAAE,mGAAA,SAAS,OAAA;AAAE,6FAAA,GAAG,OAAA;AAAE,qGAAA,WAAW,OAAA;AACnF,2CAAsD;AAA7C,oGAAA,MAAM,OAAA;AAAE,4GAAA,cAAc,OAAA;AAC/B,qCAA0C;AAAjC,wGAAA,aAAa,OAAA"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Test runner: describe, it, beforeAll, afterAll, beforeEach, afterEach.
3
+ * Runs suites and tests, collects results.
4
+ */
5
+ import type { TestSuite, RunResult, TestFn, HookFn } from './types';
6
+ declare function resetRunner(): void;
7
+ export declare function describe(name: string, fn: () => void): void;
8
+ export declare namespace describe {
9
+ var only: (name: string, fn: () => void) => void;
10
+ var skip: (name: string, fn: () => void) => void;
11
+ }
12
+ export declare function it(name: string, fn: TestFn): void;
13
+ export declare namespace it {
14
+ var only: (name: string, fn: TestFn) => void;
15
+ var skip: (name: string, fn: TestFn) => void;
16
+ }
17
+ export declare function beforeAll(fn: HookFn): void;
18
+ export declare function afterAll(fn: HookFn): void;
19
+ export declare function beforeEach(fn: HookFn): void;
20
+ export declare function afterEach(fn: HookFn): void;
21
+ export declare function run(): Promise<RunResult>;
22
+ export declare function getRootSuite(): TestSuite;
23
+ export declare function setRootSuite(suite: TestSuite): void;
24
+ export { resetRunner };
25
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAY,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAqB9E,iBAAS,WAAW,IAAI,IAAI,CAI3B;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAO3D;yBAPe,QAAQ;qBASoB,MAAM,MAAM,MAAM,IAAI,KAAG,IAAI;qBAW7B,MAAM,MAAM,MAAM,IAAI,KAAG,IAAI;;AAUzE,wBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEjD;yBAFe,EAAE;qBAIc,MAAM,MAAM,MAAM,KAAG,IAAI;qBAKzB,MAAM,MAAM,MAAM,KAAG,IAAI;;AAIzD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEzC;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE1C;AAiED,wBAAsB,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAa9C;AAED,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
package/dist/runner.js ADDED
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ /**
3
+ * Test runner: describe, it, beforeAll, afterAll, beforeEach, afterEach.
4
+ * Runs suites and tests, collects results.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.describe = describe;
8
+ exports.it = it;
9
+ exports.beforeAll = beforeAll;
10
+ exports.afterAll = afterAll;
11
+ exports.beforeEach = beforeEach;
12
+ exports.afterEach = afterEach;
13
+ exports.run = run;
14
+ exports.getRootSuite = getRootSuite;
15
+ exports.setRootSuite = setRootSuite;
16
+ exports.resetRunner = resetRunner;
17
+ let rootSuite = makeSuite('root');
18
+ let currentSuite = rootSuite;
19
+ let hasOnly = false;
20
+ function makeSuite(name) {
21
+ return {
22
+ name,
23
+ suites: [],
24
+ tests: [],
25
+ beforeAll: [],
26
+ afterAll: [],
27
+ beforeEach: [],
28
+ afterEach: [],
29
+ only: false,
30
+ skip: false,
31
+ };
32
+ }
33
+ function resetRunner() {
34
+ rootSuite = makeSuite('root');
35
+ currentSuite = rootSuite;
36
+ hasOnly = false;
37
+ }
38
+ function describe(name, fn) {
39
+ const parent = currentSuite;
40
+ const suite = makeSuite(name);
41
+ parent.suites.push(suite);
42
+ currentSuite = suite;
43
+ fn();
44
+ currentSuite = parent;
45
+ }
46
+ describe.only = function describeOnly(name, fn) {
47
+ const parent = currentSuite;
48
+ const suite = makeSuite(name);
49
+ suite.only = true;
50
+ hasOnly = true;
51
+ parent.suites.push(suite);
52
+ currentSuite = suite;
53
+ fn();
54
+ currentSuite = parent;
55
+ };
56
+ describe.skip = function describeSkip(name, fn) {
57
+ const parent = currentSuite;
58
+ const suite = makeSuite(name);
59
+ suite.skip = true;
60
+ parent.suites.push(suite);
61
+ currentSuite = suite;
62
+ fn();
63
+ currentSuite = parent;
64
+ };
65
+ function it(name, fn) {
66
+ currentSuite.tests.push({ name, fn, only: false, skip: false });
67
+ }
68
+ it.only = function itOnly(name, fn) {
69
+ currentSuite.tests.push({ name, fn, only: true, skip: false });
70
+ hasOnly = true;
71
+ };
72
+ it.skip = function itSkip(name, fn) {
73
+ currentSuite.tests.push({ name, fn, only: false, skip: true });
74
+ };
75
+ function beforeAll(fn) {
76
+ currentSuite.beforeAll.push(fn);
77
+ }
78
+ function afterAll(fn) {
79
+ currentSuite.afterAll.push(fn);
80
+ }
81
+ function beforeEach(fn) {
82
+ currentSuite.beforeEach.push(fn);
83
+ }
84
+ function afterEach(fn) {
85
+ currentSuite.afterEach.push(fn);
86
+ }
87
+ async function runHooks(hooks) {
88
+ for (const hook of hooks) {
89
+ await Promise.resolve(hook());
90
+ }
91
+ }
92
+ function shouldRunSuite(suite) {
93
+ if (suite.skip)
94
+ return false;
95
+ if (hasOnly && !suite.only && !suiteHasOnly(suite))
96
+ return false;
97
+ return true;
98
+ }
99
+ function suiteHasOnly(s) {
100
+ if (s.only)
101
+ return true;
102
+ if (s.tests.some((t) => t.only))
103
+ return true;
104
+ return s.suites.some(suiteHasOnly);
105
+ }
106
+ async function runSuite(suite, path, result, startTime) {
107
+ if (!shouldRunSuite(suite))
108
+ return;
109
+ const fullPath = path ? `${path} > ${suite.name}` : suite.name;
110
+ await runHooks(suite.beforeAll);
111
+ for (const test of suite.tests) {
112
+ const runTest = !test.skip && (!hasOnly || test.only);
113
+ if (!runTest) {
114
+ result.skipped++;
115
+ result.total++;
116
+ continue;
117
+ }
118
+ result.total++;
119
+ const testStart = Date.now();
120
+ try {
121
+ await runHooks(suite.beforeEach);
122
+ await Promise.resolve(test.fn());
123
+ await runHooks(suite.afterEach);
124
+ result.passed++;
125
+ }
126
+ catch (err) {
127
+ await runHooks(suite.afterEach).catch(() => { });
128
+ result.failed++;
129
+ result.errors.push({
130
+ suite: fullPath,
131
+ test: test.name,
132
+ error: err instanceof Error ? err : new Error(String(err)),
133
+ });
134
+ }
135
+ }
136
+ for (const child of suite.suites) {
137
+ await runSuite(child, fullPath, result, startTime);
138
+ }
139
+ await runHooks(suite.afterAll);
140
+ }
141
+ async function run() {
142
+ const result = {
143
+ passed: 0,
144
+ failed: 0,
145
+ skipped: 0,
146
+ total: 0,
147
+ duration: 0,
148
+ errors: [],
149
+ };
150
+ const start = Date.now();
151
+ await runSuite(rootSuite, '', result, start);
152
+ result.duration = Date.now() - start;
153
+ return result;
154
+ }
155
+ function getRootSuite() {
156
+ return rootSuite;
157
+ }
158
+ function setRootSuite(suite) {
159
+ rootSuite = suite;
160
+ currentSuite = suite;
161
+ }
162
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AA6BH,4BAOC;AAuBD,gBAEC;AAWD,8BAEC;AAED,4BAEC;AAED,gCAEC;AAED,8BAEC;AAiED,kBAaC;AAED,oCAEC;AAED,oCAGC;AAEQ,kCAAW;AA1KpB,IAAI,SAAS,GAAc,SAAS,CAAC,MAAM,CAAC,CAAC;AAC7C,IAAI,YAAY,GAAc,SAAS,CAAC;AACxC,IAAI,OAAO,GAAG,KAAK,CAAC;AAEpB,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,EAAE;QACb,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,KAAK;KACZ,CAAC;AACJ,CAAC;AAED,SAAS,WAAW;IAClB,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9B,YAAY,GAAG,SAAS,CAAC;IACzB,OAAO,GAAG,KAAK,CAAC;AAClB,CAAC;AAED,SAAgB,QAAQ,CAAC,IAAY,EAAE,EAAc;IACnD,MAAM,MAAM,GAAG,YAAY,CAAC;IAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,YAAY,GAAG,KAAK,CAAC;IACrB,EAAE,EAAE,CAAC;IACL,YAAY,GAAG,MAAM,CAAC;AACxB,CAAC;AAED,QAAQ,CAAC,IAAI,GAAG,SAAS,YAAY,CAAC,IAAY,EAAE,EAAc;IAChE,MAAM,MAAM,GAAG,YAAY,CAAC;IAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,GAAG,IAAI,CAAC;IACf,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,YAAY,GAAG,KAAK,CAAC;IACrB,EAAE,EAAE,CAAC;IACL,YAAY,GAAG,MAAM,CAAC;AACxB,CAAC,CAAC;AAEF,QAAQ,CAAC,IAAI,GAAG,SAAS,YAAY,CAAC,IAAY,EAAE,EAAc;IAChE,MAAM,MAAM,GAAG,YAAY,CAAC;IAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,YAAY,GAAG,KAAK,CAAC;IACrB,EAAE,EAAE,CAAC;IACL,YAAY,GAAG,MAAM,CAAC;AACxB,CAAC,CAAC;AAEF,SAAgB,EAAE,CAAC,IAAY,EAAE,EAAU;IACzC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,EAAE,CAAC,IAAI,GAAG,SAAS,MAAM,CAAC,IAAY,EAAE,EAAU;IAChD,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC,CAAC;AAEF,EAAE,CAAC,IAAI,GAAG,SAAS,MAAM,CAAC,IAAY,EAAE,EAAU;IAChD,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACjE,CAAC,CAAC;AAEF,SAAgB,SAAS,CAAC,EAAU;IAClC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,SAAgB,QAAQ,CAAC,EAAU;IACjC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,SAAgB,UAAU,CAAC,EAAU;IACnC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,SAAgB,SAAS,CAAC,EAAU;IAClC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,KAAe;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAgB;IACtC,IAAI,KAAK,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAC7B,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACjE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,CAAY;IAChC,IAAI,CAAC,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,KAAgB,EAChB,IAAY,EACZ,MAAiB,EACjB,SAAiB;IAEjB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO;IAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAE/D,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QAED,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACjC,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACjC,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAChC,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;gBACjB,KAAK,EAAE,QAAQ;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;aAC3D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAEM,KAAK,UAAU,GAAG;IACvB,MAAM,MAAM,GAAc;QACxB,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,CAAC;QACR,QAAQ,EAAE,CAAC;QACX,MAAM,EAAE,EAAE;KACX,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,QAAQ,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IACrC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,YAAY;IAC1B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,YAAY,CAAC,KAAgB;IAC3C,SAAS,GAAG,KAAK,CAAC;IAClB,YAAY,GAAG,KAAK,CAAC;AACvB,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Internal types for the test runner.
3
+ */
4
+ export type TestFn = () => void | Promise<void>;
5
+ export type HookFn = () => void | Promise<void>;
6
+ export interface TestCase {
7
+ name: string;
8
+ fn: TestFn;
9
+ only: boolean;
10
+ skip: boolean;
11
+ }
12
+ export interface TestSuite {
13
+ name: string;
14
+ suites: TestSuite[];
15
+ tests: TestCase[];
16
+ beforeAll: HookFn[];
17
+ afterAll: HookFn[];
18
+ beforeEach: HookFn[];
19
+ afterEach: HookFn[];
20
+ only: boolean;
21
+ skip: boolean;
22
+ }
23
+ export interface RunResult {
24
+ passed: number;
25
+ failed: number;
26
+ skipped: number;
27
+ total: number;
28
+ duration: number;
29
+ errors: Array<{
30
+ suite: string;
31
+ test: string;
32
+ error: Error;
33
+ }>;
34
+ }
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,MAAM,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAChD,MAAM,MAAM,MAAM,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;CAC9D"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Internal types for the test runner.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;GAEG"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "cstesting",
3
+ "version": "0.1.0",
4
+ "description": "A simple, extensible Node.js testing framework — start with a test runner and assertions, extend with browser automation later.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "cstesting": "dist/cli.js",
9
+ "cst": "dist/cli.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "node dist/cli.js",
14
+ "test:example": "node dist/cli.js example/",
15
+ "example": "npm run build && npm run test:example",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "testing",
20
+ "test-runner",
21
+ "assertions",
22
+ "nodejs",
23
+ "automation"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/YOUR_USERNAME/cstesting.git"
30
+ },
31
+ "homepage": "https://github.com/YOUR_USERNAME/cstesting#readme",
32
+ "engines": {
33
+ "node": ">=16.0.0"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md"
38
+ ],
39
+ "dependencies": {
40
+ "chrome-launcher": "^1.0.0",
41
+ "chrome-remote-interface": "^0.33.2"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^20.10.0",
45
+ "typescript": "^5.3.0"
46
+ }
47
+ }