twd-js 0.1.2 → 0.2.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 +125 -53
- package/dist/cli.js +35 -0
- package/dist/commands/{mockResponses.d.ts → mockBridge.d.ts} +17 -3
- package/dist/mock-sw.js +1 -0
- package/dist/twd.d.ts +33 -2
- package/dist/twd.es.js +283 -269
- package/dist/twd.umd.js +5 -5
- package/dist/ui/TestListItem.d.ts +20 -0
- package/package.json +29 -4
package/README.md
CHANGED
|
@@ -3,12 +3,26 @@
|
|
|
3
3
|
[](https://github.com/BRIKEV/twd/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/twd-js)
|
|
5
5
|
[](./LICENSE)
|
|
6
|
+
[](https://qlty.sh/gh/BRIKEV/projects/twd)
|
|
7
|
+
[](https://qlty.sh/gh/BRIKEV/projects/twd)
|
|
6
8
|
|
|
7
9
|
> ⚠️ This is a **beta release** – expect frequent updates and possible breaking changes.
|
|
8
10
|
|
|
9
|
-
TWD (Testing Web Development) is a tool designed to help integrating testing while developing web applications. It aims to streamline the testing process and make it easier for developers to write and run tests as they build their applications.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
TWD (Testing Web Development) is a library designed to seamlessly integrate testing into your web development workflow. It streamlines the process of writing, running, and managing tests directly in your application, with a modern UI and powerful mocking capabilities.
|
|
13
|
+
|
|
14
|
+
Currently, TWD supports React, with plans to add more frameworks soon.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- 🧪 **In-browser test runner** with a beautiful sidebar UI
|
|
21
|
+
- ⚡ **Instant feedback** as you develop
|
|
22
|
+
- 🔥 **Mock Service Worker** integration for API/request mocking
|
|
23
|
+
- 📝 **Simple, readable test syntax** (inspired by popular test frameworks)
|
|
24
|
+
- 🧩 **Automatic test discovery** with Vite support
|
|
25
|
+
- 🛠️ **Works with React** (support for more frameworks coming)
|
|
12
26
|
|
|
13
27
|
## Installation
|
|
14
28
|
|
|
@@ -25,74 +39,132 @@ yarn add twd-js
|
|
|
25
39
|
pnpm add twd-js
|
|
26
40
|
```
|
|
27
41
|
|
|
28
|
-
## How to use
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
1. **Add the TWD Sidebar to your React app:**
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { StrictMode } from 'react';
|
|
49
|
+
import { createRoot } from 'react-dom/client';
|
|
50
|
+
import App from './App';
|
|
51
|
+
import './index.css';
|
|
52
|
+
import { TWDSidebar } from 'twd-js';
|
|
53
|
+
|
|
54
|
+
createRoot(document.getElementById('root')!).render(
|
|
55
|
+
<StrictMode>
|
|
56
|
+
<App />
|
|
57
|
+
<TWDSidebar />
|
|
58
|
+
</StrictMode>,
|
|
59
|
+
);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
2. **Write your tests:**
|
|
63
|
+
|
|
64
|
+
Create files ending with `.twd.test.ts` (or any extension you prefer):
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// src/app.twd.test.ts
|
|
68
|
+
import { describe, it, twd } from "twd-js";
|
|
69
|
+
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
// Reset state before each test
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("App interactions", () => {
|
|
75
|
+
it("clicks the button", async () => {
|
|
76
|
+
twd.visit("/");
|
|
77
|
+
const btn = await twd.get("button");
|
|
78
|
+
btn.click();
|
|
79
|
+
const message = await twd.get("#message");
|
|
80
|
+
message.should("have.text", "Hello");
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
3. **Auto-load your tests:**
|
|
86
|
+
|
|
87
|
+
- With Vite:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// src/loadTests.ts
|
|
91
|
+
const modules = import.meta.glob("./**/*.twd.test.ts", { eager: true });
|
|
92
|
+
// No need to export anything
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- Or manually:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
// src/loadTests.ts
|
|
99
|
+
import "./app.twd.test";
|
|
100
|
+
import "./another-test-file.twd.test";
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Import `loadTests.ts` in your main entry (e.g., `main.tsx`):
|
|
31
104
|
|
|
32
|
-
```tsx
|
|
33
|
-
import
|
|
34
|
-
|
|
35
|
-
import './index.css'
|
|
36
|
-
import { TWDSidebar } from 'twd-js'
|
|
37
|
-
import router from './routes.ts'
|
|
38
|
-
import { RouterProvider } from 'react-router'
|
|
105
|
+
```tsx
|
|
106
|
+
import './loadTests';
|
|
107
|
+
```
|
|
39
108
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
109
|
+
4. **Run your app and open the TWD sidebar** to see and run your tests in the browser.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Mock Service Worker (API Mocking)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
TWD provides a CLI to easily set up a mock service worker for API/request mocking in your app. You do **not** need to manually register the service worker in your app—TWD handles this automatically when you use `twd.initRequestMocking()` in your tests.
|
|
117
|
+
|
|
118
|
+
### Install the mock service worker
|
|
119
|
+
|
|
120
|
+
Run the following command in your project root:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx twd-mock init <public-dir> [--save]
|
|
46
124
|
```
|
|
47
125
|
|
|
48
|
-
|
|
126
|
+
- Replace `<public-dir>` with the path to your app's public/static directory (e.g., `public/` or `dist/`).
|
|
127
|
+
- Use `--save` to print a registration snippet for your app.
|
|
49
128
|
|
|
50
|
-
|
|
51
|
-
// src/app.twd.test.ts
|
|
52
|
-
import { describe, it, twd } from "twd-js";
|
|
129
|
+
This will copy `mock-sw.js` to your public directory.
|
|
53
130
|
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
console.log("Reset state before each test");
|
|
56
|
-
});
|
|
57
131
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
132
|
+
### How to use request mocking in your tests
|
|
133
|
+
|
|
134
|
+
Just call `await twd.initRequestMocking()` at the start of your test, then use `twd.mockRequest` to define your mocks. Example:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
it("fetches a message", async () => {
|
|
138
|
+
await twd.initRequestMocking();
|
|
139
|
+
await twd.mockRequest("message", {
|
|
140
|
+
method: "GET",
|
|
141
|
+
url: "https://api.example.com/message",
|
|
142
|
+
response: {
|
|
143
|
+
value: "Mocked message!",
|
|
144
|
+
},
|
|
67
145
|
});
|
|
146
|
+
const btn = await twd.get("button[data-twd='message-button']");
|
|
147
|
+
btn.click();
|
|
148
|
+
await twd.waitForRequest("message");
|
|
149
|
+
const messageText = await twd.get("p[data-twd='message-text']");
|
|
150
|
+
messageText.should("have.text", "Mocked message!");
|
|
68
151
|
});
|
|
69
152
|
```
|
|
70
153
|
|
|
71
|
-
|
|
154
|
+
---
|
|
72
155
|
|
|
73
|
-
|
|
74
|
-
// src/loadTests.ts
|
|
75
|
-
import "./app.twd.test";
|
|
76
|
-
import "./another-test-file.twd.test";
|
|
77
|
-
// Import other test files here
|
|
78
|
-
```
|
|
156
|
+
## More Usage Examples
|
|
79
157
|
|
|
80
|
-
|
|
158
|
+
See the [examples](https://github.com/BRIKEV/twd/tree/main/examples) directory for more scenarios and advanced usage.
|
|
81
159
|
|
|
82
|
-
|
|
83
|
-
// This automatically imports all files ending with .twd.test.ts
|
|
84
|
-
const modules = import.meta.glob("./**/*.twd.test.ts", { eager: true });
|
|
160
|
+
---
|
|
85
161
|
|
|
86
|
-
|
|
87
|
-
// will cause the test files to execute and register their tests.
|
|
88
|
-
```
|
|
162
|
+
## Contributing
|
|
89
163
|
|
|
90
|
-
|
|
164
|
+
Contributions are welcome! Please open issues or pull requests on [GitHub](https://github.com/BRIKEV/twd).
|
|
91
165
|
|
|
92
|
-
|
|
93
|
-
import './loadTests' // Import test files
|
|
94
|
-
```
|
|
166
|
+
---
|
|
95
167
|
|
|
96
|
-
|
|
168
|
+
## License
|
|
97
169
|
|
|
98
|
-
|
|
170
|
+
This project is licensed under the [MIT License](./LICENSE).
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
const [, , command, targetDir, ...flags] = process.argv;
|
|
9
|
+
|
|
10
|
+
if (command !== "init") {
|
|
11
|
+
console.error("Usage: npx twd-mock init <public-dir> [--save]");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!targetDir) {
|
|
16
|
+
console.error("❌ You must provide a target public dir");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const save = flags.includes("--save");
|
|
21
|
+
const src = path.join(__dirname, "../dist/mock-sw.js");
|
|
22
|
+
const dest = path.resolve(process.cwd(), targetDir, "mock-sw.js");
|
|
23
|
+
|
|
24
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
25
|
+
fs.copyFileSync(src, dest);
|
|
26
|
+
|
|
27
|
+
console.log(`✅ mock-sw.js copied to ${dest}`);
|
|
28
|
+
if (save) {
|
|
29
|
+
console.log("💡 Remember to register it in your app:");
|
|
30
|
+
console.log(`
|
|
31
|
+
if ("serviceWorker" in navigator) {
|
|
32
|
+
navigator.serviceWorker.register("/mock-sw.js?v=1");
|
|
33
|
+
}
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
@@ -2,7 +2,7 @@ export type Rule = {
|
|
|
2
2
|
method: string;
|
|
3
3
|
url: string | RegExp;
|
|
4
4
|
response: unknown;
|
|
5
|
-
alias
|
|
5
|
+
alias: string;
|
|
6
6
|
executed?: boolean;
|
|
7
7
|
request?: unknown;
|
|
8
8
|
status?: number;
|
|
@@ -15,6 +15,11 @@ export interface Options {
|
|
|
15
15
|
status?: number;
|
|
16
16
|
headers?: Record<string, string>;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Initialize the mocking service worker.
|
|
20
|
+
* Call this once before using `mockRequest` or `waitFor`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const initRequestMocking: () => Promise<void>;
|
|
18
23
|
/**
|
|
19
24
|
* Mock a network request.
|
|
20
25
|
*
|
|
@@ -37,10 +42,19 @@ export interface Options {
|
|
|
37
42
|
* });
|
|
38
43
|
* ```
|
|
39
44
|
*/
|
|
40
|
-
export declare const mockRequest: (alias: string, options: Options) => void
|
|
45
|
+
export declare const mockRequest: (alias: string, options: Options) => Promise<void>;
|
|
41
46
|
/**
|
|
42
47
|
* Wait for a mocked request to be made.
|
|
43
48
|
* @param alias The alias of the mock rule to wait for
|
|
44
49
|
* @returns The matched rule (with body if applicable)
|
|
45
50
|
*/
|
|
46
|
-
export declare const
|
|
51
|
+
export declare const waitForRequest: (alias: string) => Promise<Rule>;
|
|
52
|
+
/**
|
|
53
|
+
* Get the current list of request mock rules.
|
|
54
|
+
* @returns The current list of request mock rules.
|
|
55
|
+
*/
|
|
56
|
+
export declare const getRequestMockRules: () => Rule[];
|
|
57
|
+
/**
|
|
58
|
+
* Clear all request mock rules.
|
|
59
|
+
*/
|
|
60
|
+
export declare const clearRequestMockRules: () => void;
|
package/dist/mock-sw.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function i(t,n,s){return s.find(e=>e.method===t&&(typeof e.url=="string"?e.url===n:new RegExp(e.url).test(n)))}function r(t,n,s){t.forEach(e=>e.postMessage({type:"EXECUTED",alias:n.alias,request:s}))}let l=[];self.addEventListener("fetch",t=>{const{method:n}=t.request,s=t.request.url,e=i(n,s,l);e&&(console.log("Mock hit:",e.alias,n,s),t.respondWith((async()=>{let a=null;try{a=await t.request.clone().text()}catch{}return self.clients.matchAll().then(o=>{r(o,e,a)}),new Response(JSON.stringify(e.response),{status:e.status||200,headers:e.headers||{"Content-Type":"application/json"}})})()))});self.addEventListener("message",t=>{const{type:n,rule:s}=t.data||{};n==="ADD_RULE"&&(l=l.filter(e=>e.alias!==s.alias),l.push(s),console.log("Rule added:",s))});
|
package/dist/twd.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Options, Rule } from './commands/
|
|
1
|
+
import { Options, Rule } from './commands/mockBridge';
|
|
2
2
|
import { TWDElemAPI } from './twd-types';
|
|
3
3
|
import { URLCommandAPI } from './commands/url';
|
|
4
4
|
/**
|
|
@@ -95,7 +95,7 @@ interface TWDAPI {
|
|
|
95
95
|
*
|
|
96
96
|
* ```
|
|
97
97
|
*/
|
|
98
|
-
|
|
98
|
+
waitForRequest: (alias: string) => Promise<Rule>;
|
|
99
99
|
/**
|
|
100
100
|
* URL-related assertions.
|
|
101
101
|
*
|
|
@@ -107,6 +107,37 @@ interface TWDAPI {
|
|
|
107
107
|
* ```
|
|
108
108
|
*/
|
|
109
109
|
url: () => URLCommandAPI;
|
|
110
|
+
/**
|
|
111
|
+
* Initializes request mocking (registers the service worker).
|
|
112
|
+
* Must be called before using `twd.mockRequest()`.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* await twd.initRequestMocking();
|
|
117
|
+
*
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
initRequestMocking: () => Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* Clears all request mock rules.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* twd.clearRequestMockRules();
|
|
127
|
+
*
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
clearRequestMockRules: () => void;
|
|
131
|
+
/**
|
|
132
|
+
* Gets all current request mock rules.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* const rules = twd.getRequestMockRules();
|
|
137
|
+
* console.log(rules);
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
getRequestMockRules: () => Rule[];
|
|
110
141
|
}
|
|
111
142
|
/**
|
|
112
143
|
* Mini Cypress-style helpers for DOM testing.
|