Skip to content

Commit fef815f

Browse files
authored
feat: add support to other types (#66)
* feat: add support to other types * fix: error exporting
1 parent dba0cdf commit fef815f

7 files changed

Lines changed: 175 additions & 4 deletions

File tree

examples/my-twd-app/src/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { RouterProvider } from 'react-router'
88
if (import.meta.env.DEV) {
99
// You choose how to load the tests; this example uses Vite's glob import
1010
const testModules = import.meta.glob("./**/*.twd.test.ts");
11-
const { initTests, twd, TWDSidebar } = await import('../../../src');
11+
const { initTests, twd, TWDSidebar } = await import('../../../src/index.ts');
1212
// You need to pass the test modules, the sidebar component, and createRoot function
1313
initTests(testModules, <TWDSidebar open={true} position="left" />, createRoot);
1414
// if you want to use mock requests, you can initialize it here

examples/my-twd-app/src/pages/Contact.tsx

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import React, { useState } from 'react';
33
const Contact: React.FC = () => {
44
const [email, setEmail] = useState('');
55
const [message, setMessage] = useState('');
6+
const [date, setDate] = useState('');
7+
const [month, setMonth] = useState('');
8+
const [time, setTime] = useState('');
9+
const [color, setColor] = useState('#000000');
10+
const [range, setRange] = useState('50');
11+
const [hour, setHour] = useState('12:00');
12+
const [week, setWeek] = useState('');
613
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
714

815
const handleSubmit = async (e: React.FormEvent) => {
@@ -14,12 +21,19 @@ const Contact: React.FC = () => {
1421
headers: {
1522
'Content-Type': 'application/json',
1623
},
17-
body: JSON.stringify({ email, message }),
24+
body: JSON.stringify({ email, message, date, month, time, color, range, hour, week }),
1825
});
1926
if (response.ok) {
2027
setStatus('success');
2128
setEmail('');
2229
setMessage('');
30+
setDate('');
31+
setMonth('');
32+
setTime('');
33+
setColor('#000000');
34+
setRange('50');
35+
setHour('12:00');
36+
setWeek('');
2337
} else {
2438
setStatus('error');
2539
}
@@ -56,6 +70,88 @@ const Contact: React.FC = () => {
5670
style={{ width: '100%', padding: '0.5rem' }}
5771
/>
5872
</div>
73+
<div style={{ marginBottom: '1rem' }}>
74+
<label htmlFor="date">Date:</label><br />
75+
<input
76+
id="date"
77+
type="date"
78+
name="date"
79+
value={date}
80+
onChange={e => setDate(e.target.value)}
81+
style={{ width: '100%', padding: '0.5rem' }}
82+
/>
83+
</div>
84+
<div style={{ marginBottom: '1rem' }}>
85+
<label htmlFor="month">Month:</label><br />
86+
<input
87+
id="month"
88+
type="month"
89+
name="month"
90+
value={month}
91+
onChange={e => setMonth(e.target.value)}
92+
style={{ width: '100%', padding: '0.5rem' }}
93+
/>
94+
</div>
95+
<div style={{ marginBottom: '1rem' }}>
96+
<label htmlFor="time">Time:</label><br />
97+
<input
98+
id="time"
99+
type="time"
100+
name="time"
101+
value={time}
102+
onChange={e => setTime(e.target.value)}
103+
style={{ width: '100%', padding: '0.5rem' }}
104+
/>
105+
</div>
106+
<div style={{ marginBottom: '1rem' }}>
107+
<label htmlFor="color">Color:</label><br />
108+
<input
109+
id="color"
110+
type="color"
111+
name="color"
112+
value={color}
113+
onChange={e => setColor(e.target.value)}
114+
style={{ width: '100%', padding: '0.5rem' }}
115+
/>
116+
</div>
117+
<div style={{ marginBottom: '1rem' }}>
118+
<label htmlFor="range">Range:</label><br />
119+
<input
120+
id="range"
121+
type="range"
122+
name="range"
123+
min="0"
124+
max="100"
125+
value={range}
126+
onChange={e => setRange(e.target.value)}
127+
style={{ width: '100%', padding: '0.5rem' }}
128+
/>
129+
</div>
130+
<div style={{ marginBottom: '1rem' }}>
131+
<label htmlFor="hour">Hour:</label><br />
132+
<input
133+
id="hour"
134+
type="time"
135+
name="hour"
136+
min="0"
137+
max="23"
138+
value={hour}
139+
onChange={e => setHour(e.target.value)}
140+
style={{ width: '100%', padding: '0.5rem' }}
141+
/>
142+
</div>
143+
add week input
144+
<div style={{ marginBottom: '1rem' }}>
145+
<label htmlFor="week">Week:</label><br />
146+
<input
147+
id="week"
148+
type="week"
149+
name="week"
150+
value={week}
151+
onChange={e => setWeek(e.target.value)}
152+
style={{ width: '100%', padding: '0.5rem' }}
153+
/>
154+
</div>
59155
<button type="submit" disabled={status === 'loading'} style={{ padding: '0.5rem 1rem' }}>
60156
{status === 'loading' ? 'Sending...' : 'Send'}
61157
</button>

examples/my-twd-app/src/twd-tests/app.twd.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,25 @@ describe("App interactions", () => {
9494
await user.type(emailInput.el, "test@example.com");
9595
const messageInput = await twd.get("textarea#message");
9696
await user.type(messageInput.el, "Hello, this is a test message.");
97+
const dateInput = await twd.get("input#date");
98+
await user.type(dateInput.el, "2023-01-01");
99+
const monthInput = await twd.get("input#month");
100+
await user.type(monthInput.el, "2023-01");
101+
const timeInput = await twd.get("input#time");
102+
await user.type(timeInput.el, "12:00");
103+
const weekInput = await twd.get("input#week");
104+
await user.type(weekInput.el, "2023-W15");
105+
const colorInput = await twd.get("input#color");
106+
twd.setInputValue(colorInput.el, '#ff0000');
107+
const rangeInput = await twd.get("input#range");
108+
twd.setInputValue(rangeInput.el, '75');
109+
const hourInput = await twd.get('input[name="hour"]');
110+
twd.setInputValue(hourInput.el, '14:30');
97111
const submitBtn = await twd.get("button[type='submit']");
98112
await user.click(submitBtn.el);
99113
const rules = await twd.waitForRequests(["contactSubmit"]);
100114
const request = rules[0].request;
101-
expect(request).to.deep.equal({ email: "test@example.com", message: "Hello, this is a test message." });
115+
expect(request).to.deep.equal({ email: "test@example.com", message: "Hello, this is a test message.", date: "2023-01-01", month: "2023-01", time: "12:00", color: "#ff0000", range: "75", hour: "14:30", week: "2023-W15" });
102116
twd.url().should("contain.url", "/contact");
103117
twd.clearRequestMockRules();
104118
});

examples/my-twd-app/vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { defineConfig } from 'vite'
22
import react from '@vitejs/plugin-react'
3+
// import { removeMockServiceWorker } from '../../src';
34

45
// https://vite.dev/config/
56
export default defineConfig({

src/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
export * from './twd';
1+
export {
2+
beforeEach,
3+
describe,
4+
it,
5+
itOnly,
6+
itSkip,
7+
twd,
8+
} from './twd';
29
import { config } from 'chai';
310
export { TWDSidebar } from './ui/TWDSidebar';
411
export { initTests } from './initializers/initTests';
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { beforeEach, describe, it } from 'vitest';
2+
import { twd } from '../../..';
3+
4+
describe('twd setInputValue command', () => {
5+
let div: HTMLDivElement;
6+
7+
beforeEach(() => {
8+
document.body.innerHTML = '';
9+
const appContainer = document.createElement('div');
10+
appContainer.id = 'app';
11+
document.body.appendChild(appContainer);
12+
// Create a wrapper div that would be the app container (not the sidebar)
13+
const rangeInput = document.createElement('input');
14+
rangeInput.type = 'range';
15+
rangeInput.value = '50';
16+
appContainer.appendChild(rangeInput);
17+
});
18+
19+
it('should set input value and trigger input event', async () => {
20+
const rangeInput = await twd.get('input[type="range"]');
21+
let inputEventFired = false;
22+
rangeInput.el.addEventListener('input', () => {
23+
inputEventFired = true;
24+
});
25+
26+
twd.setInputValue(rangeInput.el, '75');
27+
28+
rangeInput.should('have.value', '75');
29+
});
30+
});

src/twd.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ interface TWDAPI {
7979
*
8080
*/
8181
get: (selector: string) => Promise<TWDElemAPI>;
82+
/**
83+
* Sets the value of an input element and dispatches an input event. We recommend using this only for range, color, time inputs.
84+
* @param el The input element
85+
* @param value The value to set
86+
*
87+
* @example
88+
* ```ts
89+
* const input = await twd.get("input[type='time']");
90+
* twd.setInputValue(input.el, "13:30");
91+
*
92+
* ```
93+
*/
94+
setInputValue: (el: Element, value: string) => void;
8295
/**
8396
* Finds multiple elements by selector and returns an array of TWD APIs for them.
8497
* @param selector CSS selector
@@ -225,6 +238,16 @@ export const twd: TWDAPI = {
225238
};
226239
return api;
227240
},
241+
setInputValue: (el: Element, value: string) => {
242+
const { set } = Object.getOwnPropertyDescriptor(
243+
// @ts-expect-error we ignore this error because __proto__ exists
244+
el.__proto__,
245+
'value'
246+
)!;
247+
// @ts-expect-error we ignore this error because we know set exists
248+
set.call(el, value);
249+
el.dispatchEvent(new Event('input', { bubbles: true }));
250+
},
228251
getAll: async (selector: string): Promise<TWDElemAPI[]> => {
229252
// Prepend selector to exclude TWD sidebar elements
230253
const enhancedSelector = `body > div:not(#twd-sidebar-root) ${selector}`;

0 commit comments

Comments
 (0)