twd-js 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # twd
2
2
 
3
3
  [![CI](https://github.com/BRIKEV/twd/actions/workflows/ci.yml/badge.svg)](https://github.com/BRIKEV/twd/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/twd-js.svg)](https://www.npmjs.com/package/twd-js)
4
5
  [![license](https://img.shields.io/github/license/brikev/twd.svg)](./LICENSE)
5
6
 
6
7
  > ⚠️ This is a **beta release** – expect frequent updates and possible breaking changes.
@@ -15,13 +16,13 @@ You can install TWD via npm:
15
16
 
16
17
  ```bash
17
18
  # with npm
18
- npm install twd
19
+ npm install twd-js
19
20
 
20
21
  # with yarn
21
- yarn add twd
22
+ yarn add twd-js
22
23
 
23
24
  # with pnpm
24
- pnpm add twd
25
+ pnpm add twd-js
25
26
  ```
26
27
 
27
28
  ## How to use
@@ -32,7 +33,7 @@ Add the our React Sidebar component to your application:
32
33
  import { StrictMode } from 'react'
33
34
  import { createRoot } from 'react-dom/client'
34
35
  import './index.css'
35
- import { TWDSidebar } from '../../../src'
36
+ import { TWDSidebar } from 'twd-js'
36
37
  import router from './routes.ts'
37
38
  import { RouterProvider } from 'react-router'
38
39
 
@@ -44,11 +45,11 @@ createRoot(document.getElementById('root')!).render(
44
45
  )
45
46
  ```
46
47
 
47
- Then, create test files with the `.test.ts` or any extension you want. For example:
48
+ Then, create test files with the `twd.test.ts` or any extension you want. For example:
48
49
 
49
- ```tsx
50
- // src/app.twd-test.ts
51
- import { describe, it, twd } from "../../../src/twd";
50
+ ```ts
51
+ // src/app.twd.test.ts
52
+ import { describe, it, twd } from "twd-js";
52
53
 
53
54
  beforeEach(() => {
54
55
  console.log("Reset state before each test");
@@ -56,8 +57,13 @@ beforeEach(() => {
56
57
 
57
58
  describe("App interactions", () => {
58
59
  it("clicks the button", async () => {
60
+ twd.visit("/"); // Visit the root URL
59
61
  const btn = await twd.get("button");
60
62
  btn.click();
63
+ const message = await twd.get("#message");
64
+ // have.text
65
+ const haveText = await twd.get("#message");
66
+ haveText.should("have.text", "Hello");
61
67
  });
62
68
  });
63
69
  ```
@@ -66,8 +72,8 @@ After you create your test you need to load them in your application. You can do
66
72
 
67
73
  ```ts
68
74
  // src/loadTests.ts
69
- import "./app.twd-test";
70
- import "./another-test-file.twd-test";
75
+ import "./app.twd.test";
76
+ import "./another-test-file.twd.test";
71
77
  // Import other test files here
72
78
  ```
73
79
 
@@ -89,4 +95,4 @@ import './loadTests' // Import test files
89
95
 
90
96
  Finally, run your application and open the TWD sidebar to see and run your tests.
91
97
 
92
-
98
+ You can check the [examples](https://github.com/BRIKEV/twd/tree/main/examples) directory for more usage scenarios.
@@ -0,0 +1,2 @@
1
+ import { AnyAssertion } from '../twd-types';
2
+ export declare const runAssertion: (el: Element, name: AnyAssertion, ...args: any[]) => string;
@@ -0,0 +1,46 @@
1
+ export type Rule = {
2
+ method: string;
3
+ url: string | RegExp;
4
+ response: unknown;
5
+ alias?: string;
6
+ executed?: boolean;
7
+ request?: unknown;
8
+ status?: number;
9
+ headers?: Record<string, string>;
10
+ };
11
+ export interface Options {
12
+ method: string;
13
+ url: string | RegExp;
14
+ response: unknown;
15
+ status?: number;
16
+ headers?: Record<string, string>;
17
+ }
18
+ /**
19
+ * Mock a network request.
20
+ *
21
+ * @param alias Identifier for the mock rule. Useful for `waitFor()`.
22
+ * @param options Options to configure the mock:
23
+ * - `method`: HTTP method ("GET", "POST", …)
24
+ * - `url`: URL string or RegExp to match
25
+ * - `response`: Body of the mocked response
26
+ * - `status`: (optional) HTTP status code (default: 200)
27
+ * - `headers`: (optional) Response headers
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * mockRequest("getUser", {
32
+ * method: "GET",
33
+ * url: /\/api\/user\/\d+/,
34
+ * response: { id: 1, name: "Kevin" },
35
+ * status: 200,
36
+ * headers: { "x-mock": "true" }
37
+ * });
38
+ * ```
39
+ */
40
+ export declare const mockRequest: (alias: string, options: Options) => void;
41
+ /**
42
+ * Wait for a mocked request to be made.
43
+ * @param alias The alias of the mock rule to wait for
44
+ * @returns The matched rule (with body if applicable)
45
+ */
46
+ export declare const waitFor: (alias: string) => Promise<Rule>;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Simulates typing text into an input or textarea element, character by character,
3
+ * dispatching keydown, keypress, input, and keyup events for each character.
4
+ * This more closely mimics real user input and works with React's state updates.
5
+ *
6
+ * @param el The input or textarea element
7
+ * @param text The text to type
8
+ * @returns The input element after typing
9
+ */
10
+ declare const simulateType: (el: HTMLInputElement | HTMLTextAreaElement, text: string) => HTMLInputElement | HTMLTextAreaElement;
11
+ export { simulateType };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * All supported assertion names for the `should` function in url command
3
+ *
4
+ * @example
5
+ * twd.url().should("contain.url", "/new-page");
6
+ * twd.url().should("eq", "http://localhost:3000/new-page");
7
+ */
8
+ export type URLAssertionName = "eq" | "contain.url";
9
+ /**
10
+ * Negatable assertion names (e.g., 'not.have.text').
11
+ */
12
+ export type Negatable<T extends string> = T | `not.${T}`;
13
+ /**
14
+ * All assertion names, including negated ones.
15
+ */
16
+ export type AnyURLAssertion = Negatable<URLAssertionName>;
17
+ export type URLCommandAPI = {
18
+ location: Location;
19
+ should: (name: AnyURLAssertion, value: string) => URLCommandAPI | string;
20
+ };
21
+ /**
22
+ * Argument types for each assertion.
23
+ */
24
+ export type URLAssertionArgs = {
25
+ (name: "contain.url", urlPart: string): URLCommandAPI;
26
+ (name: "not.contain.url", urlPart: string): URLCommandAPI;
27
+ };
28
+ /**
29
+ * URL command for assertions on the current URL.
30
+ * @returns URLCommandAPI
31
+ */
32
+ declare const urlCommand: () => URLCommandAPI;
33
+ export default urlCommand;
@@ -0,0 +1,2 @@
1
+ export * from './twd';
2
+ export { TWDSidebar } from './ui/TWDSidebar';
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Types and interfaces for the TWD testing library.
3
+ *
4
+ * @module twd-types
5
+ */
6
+ /**
7
+ * All supported assertion names for the `should` function.
8
+ *
9
+ * @example
10
+ * api.should("have.text", "Hello");
11
+ * api.should("be.empty");
12
+ */
13
+ export type AssertionName = "have.text" | "contain.text" | "be.empty" | "have.attr" | "have.value" | "be.disabled" | "be.enabled" | "be.checked" | "be.selected" | "be.focused" | "be.visible" | "have.class";
14
+ /**
15
+ * Negatable assertion names (e.g., 'not.have.text').
16
+ */
17
+ export type Negatable<T extends string> = T | `not.${T}`;
18
+ /**
19
+ * All assertion names, including negated ones.
20
+ */
21
+ export type AnyAssertion = Negatable<AssertionName>;
22
+ /**
23
+ * Argument types for each assertion.
24
+ */
25
+ export type AssertionArgs = {
26
+ "have.text": [expected: string];
27
+ "contain.text": [expected: string];
28
+ "be.empty": [];
29
+ "have.attr": [attr: string, value: string];
30
+ "have.value": [value: string];
31
+ "be.disabled": [];
32
+ "be.enabled": [];
33
+ "be.checked": [];
34
+ "be.selected": [];
35
+ "be.focused": [];
36
+ "be.visible": [];
37
+ "have.class": [className: string];
38
+ };
39
+ /**
40
+ * Maps assertion name to its argument tuple.
41
+ */
42
+ export type ArgsFor<A extends AnyAssertion> = A extends `not.${infer Base extends AssertionName}` ? AssertionArgs[Base] : A extends AssertionName ? AssertionArgs[A] : never;
43
+ /**
44
+ * Overloads for the `should` function, for best IntelliSense.
45
+ *
46
+ * @example
47
+ * twd.should("have.text", "Hello");
48
+ * twd.should("be.empty");
49
+ * twd.should("have.class", "active");
50
+ */
51
+ export type ShouldFn = {
52
+ (name: "have.text", expected: string): TWDElemAPI;
53
+ (name: "not.have.text", expected: string): TWDElemAPI;
54
+ (name: "contain.text", expected: string): TWDElemAPI;
55
+ (name: "not.contain.text", expected: string): TWDElemAPI;
56
+ (name: "be.empty"): TWDElemAPI;
57
+ (name: "not.be.empty"): TWDElemAPI;
58
+ (name: "have.attr", attr: string, value: string): TWDElemAPI;
59
+ (name: "not.have.attr", attr: string, value: string): TWDElemAPI;
60
+ (name: "have.value", value: string): TWDElemAPI;
61
+ (name: "not.have.value", value: string): TWDElemAPI;
62
+ (name: "be.disabled"): TWDElemAPI;
63
+ (name: "not.be.disabled"): TWDElemAPI;
64
+ (name: "be.enabled"): TWDElemAPI;
65
+ (name: "not.be.enabled"): TWDElemAPI;
66
+ (name: "be.checked"): TWDElemAPI;
67
+ (name: "not.be.checked"): TWDElemAPI;
68
+ (name: "be.selected"): TWDElemAPI;
69
+ (name: "not.be.selected"): TWDElemAPI;
70
+ (name: "be.focused"): TWDElemAPI;
71
+ (name: "not.be.focused"): TWDElemAPI;
72
+ (name: "be.visible"): TWDElemAPI;
73
+ (name: "not.be.visible"): TWDElemAPI;
74
+ (name: "have.class", className: string): TWDElemAPI;
75
+ (name: "not.have.class", className: string): TWDElemAPI;
76
+ };
77
+ /**
78
+ * The main API returned by `twd.get()`.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const btn = await twd.get("button");
83
+ * btn.should("have.text", "Clicked").click();
84
+ *
85
+ * ```
86
+ *
87
+ */
88
+ export interface TWDElemAPI {
89
+ /** The underlying DOM element. */
90
+ el: Element;
91
+ /**
92
+ * Simulates a user click on the element.
93
+ * Returns the same API so you can chain more actions.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * const button = await twd.get("button");
98
+ * button.click();
99
+ *
100
+ * ```
101
+ *
102
+ */
103
+ click: () => void;
104
+ /**
105
+ * Types text into an input element.
106
+ * @param text The text to type.
107
+ * @returns The input element.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * const email = await twd.get("input#email");
112
+ * email.type("test@example.com");
113
+ *
114
+ * ```
115
+ *
116
+ */
117
+ type: (text: string) => HTMLInputElement | HTMLTextAreaElement;
118
+ /**
119
+ * Gets the text content of the element.
120
+ * @returns The text content.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * const para = await twd.get("p");
125
+ * const content = para.text();
126
+ * console.log(content);
127
+ *
128
+ * ```
129
+ *
130
+ */
131
+ text: () => string;
132
+ /**
133
+ * Asserts something about the element.
134
+ * @param name The name of the assertion.
135
+ * @param args Arguments for the assertion.
136
+ * @returns The same API for chaining.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const btn = await twd.get("button");
141
+ * btn.should("have.text", "Click me").should("not.be.disabled");
142
+ *
143
+ * ```
144
+ *
145
+ */
146
+ should: ShouldFn;
147
+ }
package/dist/twd.d.ts ADDED
@@ -0,0 +1,116 @@
1
+ import { Options, Rule } from './commands/mockResponses';
2
+ import { TWDElemAPI } from './twd-types';
3
+ import { URLCommandAPI } from './commands/url';
4
+ /**
5
+ * Stores the function to run before each test.
6
+ */
7
+ declare let beforeEachFn: (() => void | Promise<void>) | null;
8
+ /**
9
+ * Registers a function to run before each test.
10
+ * @example
11
+ * beforeEach(() => { ... });
12
+ */
13
+ export declare const beforeEach: (fn: typeof beforeEachFn) => void;
14
+ /**
15
+ * Groups related tests together.
16
+ * @example
17
+ * describe("My group", () => { ... });
18
+ */
19
+ export declare const describe: (name: string, fn: () => void) => void;
20
+ /**
21
+ * Defines a test case.
22
+ * @example
23
+ * it("does something", async () => { ... });
24
+ */
25
+ export declare const it: (name: string, fn: () => Promise<void> | void) => void;
26
+ /**
27
+ * Defines an exclusive test case (only this runs).
28
+ * @example
29
+ * itOnly("runs only this", async () => { ... });
30
+ */
31
+ export declare const itOnly: (name: string, fn: () => Promise<void> | void) => void;
32
+ /**
33
+ * Skips a test case.
34
+ * @example
35
+ * itSkip("skipped test", () => { ... });
36
+ */
37
+ export declare const itSkip: (name: string, _fn: () => Promise<void> | void) => void;
38
+ interface TWDAPI {
39
+ /**
40
+ * Finds an element by selector and returns the TWD API for it.
41
+ * @param selector CSS selector
42
+ * @returns {Promise<TWDElemAPI>} The TWD API for the element
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const btn = await twd.get("button");
47
+ *
48
+ * ```
49
+ *
50
+ */
51
+ get: (selector: string) => Promise<TWDElemAPI>;
52
+ /**
53
+ * Simulates visiting a URL (SPA navigation).
54
+ * @param url The URL to visit
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * twd.visit("/contact");
59
+ *
60
+ * ```
61
+ */
62
+ visit: (url: string) => void;
63
+ /**
64
+ * Mock a network request.
65
+ *
66
+ * @param alias Identifier for the mock rule. Useful for `waitFor()`.
67
+ * @param options Options to configure the mock:
68
+ * - `method`: HTTP method ("GET", "POST", …)
69
+ * - `url`: URL string or RegExp to match
70
+ * - `response`: Body of the mocked response
71
+ * - `status`: (optional) HTTP status code (default: 200)
72
+ * - `headers`: (optional) Response headers
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * mockRequest("getUser", {
77
+ * method: "GET",
78
+ * url: /\/api\/user\/\d+/,
79
+ * response: { id: 1, name: "Kevin" },
80
+ * status: 200,
81
+ * headers: { "x-mock": "true" }
82
+ * });
83
+ * ```
84
+ */
85
+ mockRequest: (alias: string, options: Options) => void;
86
+ /**
87
+ * Wait for a mocked request to be made.
88
+ * @param alias The alias of the mock rule to wait for
89
+ * @return The matched rule (with body if applicable)
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const rule = await twd.waitFor("aliasId");
94
+ * console.log(rule.body);
95
+ *
96
+ * ```
97
+ */
98
+ waitFor: (alias: string) => Promise<Rule>;
99
+ /**
100
+ * URL-related assertions.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * twd.url().should("eq", "http://localhost:3000/contact");
105
+ * twd.url().should("contain.url", "/contact");
106
+ *
107
+ * ```
108
+ */
109
+ url: () => URLCommandAPI;
110
+ }
111
+ /**
112
+ * Mini Cypress-style helpers for DOM testing.
113
+ * @namespace twd
114
+ */
115
+ export declare const twd: TWDAPI;
116
+ export {};