rescript-vitest-extras 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.
@@ -0,0 +1,190 @@
1
+ // =============================================================================
2
+ // Shared Types
3
+ // =============================================================================
4
+
5
+ /**
6
+ * Vitest Browser Locator API bindings.
7
+ *
8
+ * Provides type-safe bindings for the `@vitest/browser` Locator class, including
9
+ * query methods (getByRole, getByText, etc.), filtering, interaction, and element access.
10
+ */
11
+ /** Opaque type for the Locator object from `@vitest/browser`. */
12
+ type t
13
+
14
+ /** ARIA role, typed as string since the set is large and extensible. */
15
+ type ariaRole = string
16
+
17
+ /** Represents `string | RegExp` in the JS API. Zero-cost via `@unboxed`. */
18
+ @unboxed
19
+ type stringOrRegExp = String(string) | RegExp(RegExp.t)
20
+
21
+ // =============================================================================
22
+ // Options Types
23
+ // =============================================================================
24
+
25
+ /** Options for `getByRole` queries. All fields are optional. */
26
+ type locatorByRoleOptions = {
27
+ exact?: bool,
28
+ checked?: bool,
29
+ disabled?: bool,
30
+ expanded?: bool,
31
+ includeHidden?: bool,
32
+ level?: int,
33
+ name?: stringOrRegExp,
34
+ pressed?: bool,
35
+ selected?: bool,
36
+ }
37
+
38
+ /** Options for text-based queries and the `filter` method. */
39
+ type locatorFilterOptions = {
40
+ hasText?: stringOrRegExp,
41
+ hasNotText?: stringOrRegExp,
42
+ has?: t,
43
+ hasNot?: t,
44
+ }
45
+
46
+ // =============================================================================
47
+ // Escape Hatch
48
+ // =============================================================================
49
+
50
+ /** Wraps a raw DOM element as a Locator for APIs that accept `Element | Locator` at runtime. */
51
+ external fromElement: Dom.element => t = "%identity"
52
+
53
+ // =============================================================================
54
+ // Query Methods
55
+ // =============================================================================
56
+
57
+ /** Returns a locator for the first element matching the given ARIA role. */
58
+ @send
59
+ external getByRole: (t, ariaRole, ~options: locatorByRoleOptions=?) => t = "getByRole"
60
+
61
+ /** Returns a locator for the first element matching the given text content. */
62
+ @send
63
+ external getByText: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t = "getByText"
64
+
65
+ /** Returns a locator for the first element matching the given label text. */
66
+ @send
67
+ external getByLabelText: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t =
68
+ "getByLabelText"
69
+
70
+ /** Returns a locator for the first element matching the given placeholder text. */
71
+ @send
72
+ external getByPlaceholder: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t =
73
+ "getByPlaceholder"
74
+
75
+ /** Returns a locator for the first element matching the given alt text. */
76
+ @send
77
+ external getByAltText: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t = "getByAltText"
78
+
79
+ /** Returns a locator for the first element matching the given `data-testid` attribute. */
80
+ @send
81
+ external getByTestId: (t, stringOrRegExp) => t = "getByTestId"
82
+
83
+ /** Returns a locator for the first element matching the given title attribute. */
84
+ @send
85
+ external getByTitle: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t = "getByTitle"
86
+
87
+ // =============================================================================
88
+ // Filtering Methods
89
+ // =============================================================================
90
+
91
+ /** Returns a locator for the nth element (0-indexed) matched by this locator. */
92
+ @send
93
+ external nth: (t, int) => t = "nth"
94
+
95
+ /** Returns a locator for the first element matched by this locator. */
96
+ @send
97
+ external first: t => t = "first"
98
+
99
+ /** Returns a locator for the last element matched by this locator. */
100
+ @send
101
+ external last: t => t = "last"
102
+
103
+ /** Returns a locator matching elements that satisfy both this locator and the given locator. */
104
+ @send
105
+ external and_: (t, t) => t = "and"
106
+
107
+ /** Returns a locator matching elements that satisfy either this locator or the given locator. */
108
+ @send
109
+ external or_: (t, t) => t = "or"
110
+
111
+ /** Filters the matched elements using the provided options. */
112
+ @send
113
+ external filter: (t, locatorFilterOptions) => t = "filter"
114
+
115
+ // =============================================================================
116
+ // Interaction Methods
117
+ // =============================================================================
118
+
119
+ /** Clicks the element. Resolves when the action is complete. */
120
+ @send
121
+ external click: (t, ~options: {..}=?) => promise<unit> = "click"
122
+
123
+ /** Double-clicks the element. Resolves when the action is complete. */
124
+ @send
125
+ external dblClick: (t, ~options: {..}=?) => promise<unit> = "dblClick"
126
+
127
+ /** Triple-clicks the element. Resolves when the action is complete. */
128
+ @send
129
+ external tripleClick: (t, ~options: {..}=?) => promise<unit> = "tripleClick"
130
+
131
+ /** Clears the input element's value. Resolves when the action is complete. */
132
+ @send
133
+ external clear: (t, ~options: {..}=?) => promise<unit> = "clear"
134
+
135
+ /** Hovers over the element. Resolves when the action is complete. */
136
+ @send
137
+ external hover: (t, ~options: {..}=?) => promise<unit> = "hover"
138
+
139
+ /** Moves the pointer away from the element. Resolves when the action is complete. */
140
+ @send
141
+ external unhover: (t, ~options: {..}=?) => promise<unit> = "unhover"
142
+
143
+ /** Types the given text into the input element. Resolves when the action is complete. */
144
+ @send
145
+ external fill: (t, string, ~options: {..}=?) => promise<unit> = "fill"
146
+
147
+ /** Drags the source element and drops it onto the given target locator. */
148
+ @send
149
+ external dropTo: (t, t, ~options: {..}=?) => promise<unit> = "dropTo"
150
+
151
+ /** Selects the given options in a `<select>` element. The value type is intentionally
152
+ polymorphic to support `string`, `array<string>`, `HTMLElement`, or `array<HTMLElement>`. */
153
+ @send
154
+ external selectOptions: (t, 'a, ~options: {..}=?) => promise<unit> = "selectOptions"
155
+
156
+ /** Takes a screenshot of the element. Resolves with the screenshot path. */
157
+ @send
158
+ external screenshot: (t, ~options: {..}=?) => promise<string> = "screenshot"
159
+
160
+ // =============================================================================
161
+ // Element Access
162
+ // =============================================================================
163
+
164
+ /** Returns the matched DOM element, or `None` if no element matches. */
165
+ @send @return(nullable)
166
+ external query: t => option<Dom.element> = "query"
167
+
168
+ /** Returns the matched DOM element. Throws if no element matches. */
169
+ @send
170
+ external element: t => Dom.element = "element"
171
+
172
+ /** Returns all matched DOM elements as an array. */
173
+ @send
174
+ external elements: t => array<Dom.element> = "elements"
175
+
176
+ /** Returns all matched locators as an array. */
177
+ @send
178
+ external all: t => array<t> = "all"
179
+
180
+ // =============================================================================
181
+ // Properties
182
+ // =============================================================================
183
+
184
+ /** The CSS selector string for this locator. */
185
+ @get
186
+ external selector: t => string = "selector"
187
+
188
+ /** The number of elements matched by this locator. */
189
+ @get
190
+ external length: t => int = "length"
@@ -0,0 +1,190 @@
1
+ // =============================================================================
2
+ // Shared Types
3
+ // =============================================================================
4
+
5
+ /**
6
+ * Vitest Browser Locator API bindings.
7
+ *
8
+ * Provides type-safe bindings for the `@vitest/browser` Locator class, including
9
+ * query methods (getByRole, getByText, etc.), filtering, interaction, and element access.
10
+ */
11
+ /** Opaque type for the Locator object from `@vitest/browser`. */
12
+ type t
13
+
14
+ /** ARIA role, typed as string since the set is large and extensible. */
15
+ type ariaRole = string
16
+
17
+ /** Represents `string | RegExp` in the JS API. Zero-cost via `@unboxed`. */
18
+ @unboxed
19
+ type stringOrRegExp = String(string) | RegExp(RegExp.t)
20
+
21
+ // =============================================================================
22
+ // Options Types
23
+ // =============================================================================
24
+
25
+ /** Options for `getByRole` queries. All fields are optional. */
26
+ type locatorByRoleOptions = {
27
+ exact?: bool,
28
+ checked?: bool,
29
+ disabled?: bool,
30
+ expanded?: bool,
31
+ includeHidden?: bool,
32
+ level?: int,
33
+ name?: stringOrRegExp,
34
+ pressed?: bool,
35
+ selected?: bool,
36
+ }
37
+
38
+ /** Options for text-based queries and the `filter` method. */
39
+ type locatorFilterOptions = {
40
+ hasText?: stringOrRegExp,
41
+ hasNotText?: stringOrRegExp,
42
+ has?: t,
43
+ hasNot?: t,
44
+ }
45
+
46
+ // =============================================================================
47
+ // Escape Hatch
48
+ // =============================================================================
49
+
50
+ /** Wraps a raw DOM element as a Locator for APIs that accept `Element | Locator` at runtime. */
51
+ external fromElement: Dom.element => t = "%identity"
52
+
53
+ // =============================================================================
54
+ // Query Methods
55
+ // =============================================================================
56
+
57
+ /** Returns a locator for the first element matching the given ARIA role. */
58
+ @send
59
+ external getByRole: (t, ariaRole, ~options: locatorByRoleOptions=?) => t = "getByRole"
60
+
61
+ /** Returns a locator for the first element matching the given text content. */
62
+ @send
63
+ external getByText: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t = "getByText"
64
+
65
+ /** Returns a locator for the first element matching the given label text. */
66
+ @send
67
+ external getByLabelText: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t =
68
+ "getByLabelText"
69
+
70
+ /** Returns a locator for the first element matching the given placeholder text. */
71
+ @send
72
+ external getByPlaceholder: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t =
73
+ "getByPlaceholder"
74
+
75
+ /** Returns a locator for the first element matching the given alt text. */
76
+ @send
77
+ external getByAltText: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t = "getByAltText"
78
+
79
+ /** Returns a locator for the first element matching the given `data-testid` attribute. */
80
+ @send
81
+ external getByTestId: (t, stringOrRegExp) => t = "getByTestId"
82
+
83
+ /** Returns a locator for the first element matching the given title attribute. */
84
+ @send
85
+ external getByTitle: (t, stringOrRegExp, ~options: locatorFilterOptions=?) => t = "getByTitle"
86
+
87
+ // =============================================================================
88
+ // Filtering Methods
89
+ // =============================================================================
90
+
91
+ /** Returns a locator for the nth element (0-indexed) matched by this locator. */
92
+ @send
93
+ external nth: (t, int) => t = "nth"
94
+
95
+ /** Returns a locator for the first element matched by this locator. */
96
+ @send
97
+ external first: t => t = "first"
98
+
99
+ /** Returns a locator for the last element matched by this locator. */
100
+ @send
101
+ external last: t => t = "last"
102
+
103
+ /** Returns a locator matching elements that satisfy both this locator and the given locator. */
104
+ @send
105
+ external and_: (t, t) => t = "and"
106
+
107
+ /** Returns a locator matching elements that satisfy either this locator or the given locator. */
108
+ @send
109
+ external or_: (t, t) => t = "or"
110
+
111
+ /** Filters the matched elements using the provided options. */
112
+ @send
113
+ external filter: (t, locatorFilterOptions) => t = "filter"
114
+
115
+ // =============================================================================
116
+ // Interaction Methods
117
+ // =============================================================================
118
+
119
+ /** Clicks the element. Resolves when the action is complete. */
120
+ @send
121
+ external click: (t, ~options: {..}=?) => promise<unit> = "click"
122
+
123
+ /** Double-clicks the element. Resolves when the action is complete. */
124
+ @send
125
+ external dblClick: (t, ~options: {..}=?) => promise<unit> = "dblClick"
126
+
127
+ /** Triple-clicks the element. Resolves when the action is complete. */
128
+ @send
129
+ external tripleClick: (t, ~options: {..}=?) => promise<unit> = "tripleClick"
130
+
131
+ /** Clears the input element's value. Resolves when the action is complete. */
132
+ @send
133
+ external clear: (t, ~options: {..}=?) => promise<unit> = "clear"
134
+
135
+ /** Hovers over the element. Resolves when the action is complete. */
136
+ @send
137
+ external hover: (t, ~options: {..}=?) => promise<unit> = "hover"
138
+
139
+ /** Moves the pointer away from the element. Resolves when the action is complete. */
140
+ @send
141
+ external unhover: (t, ~options: {..}=?) => promise<unit> = "unhover"
142
+
143
+ /** Types the given text into the input element. Resolves when the action is complete. */
144
+ @send
145
+ external fill: (t, string, ~options: {..}=?) => promise<unit> = "fill"
146
+
147
+ /** Drags the source element and drops it onto the given target locator. */
148
+ @send
149
+ external dropTo: (t, t, ~options: {..}=?) => promise<unit> = "dropTo"
150
+
151
+ /** Selects the given options in a `<select>` element. The value type is intentionally
152
+ polymorphic to support `string`, `array<string>`, `HTMLElement`, or `array<HTMLElement>`. */
153
+ @send
154
+ external selectOptions: (t, 'a, ~options: {..}=?) => promise<unit> = "selectOptions"
155
+
156
+ /** Takes a screenshot of the element. Resolves with the screenshot path. */
157
+ @send
158
+ external screenshot: (t, ~options: {..}=?) => promise<string> = "screenshot"
159
+
160
+ // =============================================================================
161
+ // Element Access
162
+ // =============================================================================
163
+
164
+ /** Returns the matched DOM element, or `None` if no element matches. */
165
+ @send @return(nullable)
166
+ external query: t => option<Dom.element> = "query"
167
+
168
+ /** Returns the matched DOM element. Throws if no element matches. */
169
+ @send
170
+ external element: t => Dom.element = "element"
171
+
172
+ /** Returns all matched DOM elements as an array. */
173
+ @send
174
+ external elements: t => array<Dom.element> = "elements"
175
+
176
+ /** Returns all matched locators as an array. */
177
+ @send
178
+ external all: t => array<t> = "all"
179
+
180
+ // =============================================================================
181
+ // Properties
182
+ // =============================================================================
183
+
184
+ /** The CSS selector string for this locator. */
185
+ @get
186
+ external selector: t => string = "selector"
187
+
188
+ /** The number of elements matched by this locator. */
189
+ @get
190
+ external length: t => int = "length"
@@ -0,0 +1,119 @@
1
+ // =============================================================================
2
+ // Page Singleton
3
+ // =============================================================================
4
+
5
+ /**
6
+ * Vitest Browser Page API bindings.
7
+ *
8
+ * Wraps the `page` singleton from `vitest/browser` with ergonomic ReScript
9
+ * convenience functions. Each query method mirrors the corresponding method
10
+ * on `VitestExtras__BrowserLocator.t` but operates on the top-level page context.
11
+ */
12
+ /** Abstract type for the Page object from `vitest/browser`. */
13
+ type t
14
+
15
+ @module("vitest/browser") @val external page: t = "page"
16
+
17
+ // =============================================================================
18
+ // Query Methods
19
+ // =============================================================================
20
+
21
+ @send
22
+ external getByRoleBinding: (
23
+ t,
24
+ VitestExtras__BrowserLocator.ariaRole,
25
+ ~options: VitestExtras__BrowserLocator.locatorByRoleOptions=?,
26
+ ) => VitestExtras__BrowserLocator.t = "getByRole"
27
+
28
+ /** Returns a locator for the first element matching the given ARIA role. */
29
+ @inline
30
+ let getByRole = (~options=?, role) => page->getByRoleBinding(role, ~options?)
31
+
32
+ @send
33
+ external getByTextBinding: (
34
+ t,
35
+ VitestExtras__BrowserLocator.stringOrRegExp,
36
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
37
+ ) => VitestExtras__BrowserLocator.t = "getByText"
38
+
39
+ /** Returns a locator for the first element matching the given text content. */
40
+ @inline
41
+ let getByText = (~options=?, text) => page->getByTextBinding(text, ~options?)
42
+
43
+ @send
44
+ external getByLabelTextBinding: (
45
+ t,
46
+ VitestExtras__BrowserLocator.stringOrRegExp,
47
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
48
+ ) => VitestExtras__BrowserLocator.t = "getByLabelText"
49
+
50
+ /** Returns a locator for the first element matching the given label text. */
51
+ @inline
52
+ let getByLabelText = (~options=?, text) => page->getByLabelTextBinding(text, ~options?)
53
+
54
+ @send
55
+ external getByPlaceholderBinding: (
56
+ t,
57
+ VitestExtras__BrowserLocator.stringOrRegExp,
58
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
59
+ ) => VitestExtras__BrowserLocator.t = "getByPlaceholder"
60
+
61
+ /** Returns a locator for the first element matching the given placeholder text. */
62
+ @inline
63
+ let getByPlaceholder = (~options=?, text) => page->getByPlaceholderBinding(text, ~options?)
64
+
65
+ @send
66
+ external getByAltTextBinding: (
67
+ t,
68
+ VitestExtras__BrowserLocator.stringOrRegExp,
69
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
70
+ ) => VitestExtras__BrowserLocator.t = "getByAltText"
71
+
72
+ /** Returns a locator for the first element matching the given alt text. */
73
+ @inline
74
+ let getByAltText = (~options=?, text) => page->getByAltTextBinding(text, ~options?)
75
+
76
+ @send
77
+ external getByTestIdBinding: (
78
+ t,
79
+ VitestExtras__BrowserLocator.stringOrRegExp,
80
+ ) => VitestExtras__BrowserLocator.t = "getByTestId"
81
+
82
+ /** Returns a locator for the first element matching the given `data-testid` attribute. */
83
+ @inline
84
+ let getByTestId = testId => page->getByTestIdBinding(testId)
85
+
86
+ @send
87
+ external getByTitleBinding: (
88
+ t,
89
+ VitestExtras__BrowserLocator.stringOrRegExp,
90
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
91
+ ) => VitestExtras__BrowserLocator.t = "getByTitle"
92
+
93
+ /** Returns a locator for the first element matching the given title attribute. */
94
+ @inline
95
+ let getByTitle = (~options=?, text) => page->getByTitleBinding(text, ~options?)
96
+
97
+ // =============================================================================
98
+ // Additional Methods
99
+ // =============================================================================
100
+
101
+ @send external viewportBinding: (t, int, int) => promise<unit> = "viewport"
102
+
103
+ /** Sets the iframe viewport size. */
104
+ @inline
105
+ let viewport = (width, height) => page->viewportBinding(width, height)
106
+
107
+ @send external screenshotBinding: (t, ~options: {..}=?) => promise<string> = "screenshot"
108
+
109
+ /** Takes a screenshot of the current page. Resolves with the screenshot path. */
110
+ @inline
111
+ let screenshot = (~options=?) => page->screenshotBinding(~options?)
112
+
113
+ @send
114
+ external elementLocatorBinding: (t, Dom.element) => VitestExtras__BrowserLocator.t =
115
+ "elementLocator"
116
+
117
+ /** Wraps a DOM element in a Locator. */
118
+ @inline
119
+ let elementLocator = element => page->elementLocatorBinding(element)
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Vitest Browser Page API bindings.
3
+ *
4
+ * Wraps the `page` singleton from `vitest/browser` with ergonomic ReScript
5
+ * convenience functions. Each query method mirrors the corresponding method
6
+ * on `VitestExtras__BrowserLocator.t` but operates on the top-level page context.
7
+ */
8
+ /** Returns a locator for the first element matching the given ARIA role. */
9
+ let // =============================================================================
10
+ // Query Methods
11
+ // =============================================================================
12
+
13
+ getByRole: (
14
+ ~options: VitestExtras__BrowserLocator.locatorByRoleOptions=?,
15
+ VitestExtras__BrowserLocator.ariaRole,
16
+ ) => VitestExtras__BrowserLocator.t
17
+
18
+ /** Returns a locator for the first element matching the given text content. */
19
+ let getByText: (
20
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
21
+ VitestExtras__BrowserLocator.stringOrRegExp,
22
+ ) => VitestExtras__BrowserLocator.t
23
+
24
+ /** Returns a locator for the first element matching the given label text. */
25
+ let getByLabelText: (
26
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
27
+ VitestExtras__BrowserLocator.stringOrRegExp,
28
+ ) => VitestExtras__BrowserLocator.t
29
+
30
+ /** Returns a locator for the first element matching the given placeholder text. */
31
+ let getByPlaceholder: (
32
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
33
+ VitestExtras__BrowserLocator.stringOrRegExp,
34
+ ) => VitestExtras__BrowserLocator.t
35
+
36
+ /** Returns a locator for the first element matching the given alt text. */
37
+ let getByAltText: (
38
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
39
+ VitestExtras__BrowserLocator.stringOrRegExp,
40
+ ) => VitestExtras__BrowserLocator.t
41
+
42
+ /** Returns a locator for the first element matching the given `data-testid` attribute. */
43
+ let getByTestId: VitestExtras__BrowserLocator.stringOrRegExp => VitestExtras__BrowserLocator.t
44
+
45
+ /** Returns a locator for the first element matching the given title attribute. */
46
+ let getByTitle: (
47
+ ~options: VitestExtras__BrowserLocator.locatorFilterOptions=?,
48
+ VitestExtras__BrowserLocator.stringOrRegExp,
49
+ ) => VitestExtras__BrowserLocator.t
50
+
51
+ // =============================================================================
52
+ // Additional Methods
53
+ // =============================================================================
54
+
55
+ /** Sets the iframe viewport size. */
56
+ let viewport: (int, int) => promise<unit>
57
+
58
+ /** Takes a screenshot of the current page. Resolves with the screenshot path. */
59
+ let screenshot: (~options: {..}=?) => promise<string>
60
+
61
+ /** Wraps a DOM element in a Locator. */
62
+ let elementLocator: Dom.element => VitestExtras__BrowserLocator.t