@quickpickle/vitest-browser 0.0.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +4 -0
  4. package/dist/VitestBrowserWorld.cjs +179 -0
  5. package/dist/VitestBrowserWorld.cjs.map +1 -0
  6. package/dist/VitestBrowserWorld.d.ts +103 -0
  7. package/dist/VitestBrowserWorld.mjs +176 -0
  8. package/dist/VitestBrowserWorld.mjs.map +1 -0
  9. package/dist/actions.steps.cjs +157 -0
  10. package/dist/actions.steps.cjs.map +1 -0
  11. package/dist/actions.steps.d.ts +1 -0
  12. package/dist/actions.steps.mjs +155 -0
  13. package/dist/actions.steps.mjs.map +1 -0
  14. package/dist/frameworks/ReactBrowserWorld.cjs +38 -0
  15. package/dist/frameworks/ReactBrowserWorld.cjs.map +1 -0
  16. package/dist/frameworks/ReactBrowserWorld.d.ts +10 -0
  17. package/dist/frameworks/ReactBrowserWorld.mjs +36 -0
  18. package/dist/frameworks/ReactBrowserWorld.mjs.map +1 -0
  19. package/dist/frameworks/SvelteBrowserWorld.cjs +17 -0
  20. package/dist/frameworks/SvelteBrowserWorld.cjs.map +1 -0
  21. package/dist/frameworks/SvelteBrowserWorld.d.ts +9 -0
  22. package/dist/frameworks/SvelteBrowserWorld.mjs +15 -0
  23. package/dist/frameworks/SvelteBrowserWorld.mjs.map +1 -0
  24. package/dist/frameworks/VueBrowserWorld.cjs +25 -0
  25. package/dist/frameworks/VueBrowserWorld.cjs.map +1 -0
  26. package/dist/frameworks/VueBrowserWorld.d.ts +10 -0
  27. package/dist/frameworks/VueBrowserWorld.mjs +23 -0
  28. package/dist/frameworks/VueBrowserWorld.mjs.map +1 -0
  29. package/dist/frameworks/react.cjs +11 -0
  30. package/dist/frameworks/react.cjs.map +1 -0
  31. package/dist/frameworks/react.d.ts +1 -0
  32. package/dist/frameworks/react.mjs +9 -0
  33. package/dist/frameworks/react.mjs.map +1 -0
  34. package/dist/frameworks/svelte.cjs +10 -0
  35. package/dist/frameworks/svelte.cjs.map +1 -0
  36. package/dist/frameworks/svelte.d.ts +1 -0
  37. package/dist/frameworks/svelte.mjs +8 -0
  38. package/dist/frameworks/svelte.mjs.map +1 -0
  39. package/dist/frameworks/vue.cjs +10 -0
  40. package/dist/frameworks/vue.cjs.map +1 -0
  41. package/dist/frameworks/vue.d.ts +1 -0
  42. package/dist/frameworks/vue.mjs +8 -0
  43. package/dist/frameworks/vue.mjs.map +1 -0
  44. package/dist/outcomes.steps.cjs +186 -0
  45. package/dist/outcomes.steps.cjs.map +1 -0
  46. package/dist/outcomes.steps.d.ts +1 -0
  47. package/dist/outcomes.steps.mjs +184 -0
  48. package/dist/outcomes.steps.mjs.map +1 -0
  49. package/package.json +103 -0
  50. package/rollup.config.js +58 -0
  51. package/src/VitestBrowserWorld.ts +205 -0
  52. package/src/actions.steps.ts +169 -0
  53. package/src/frameworks/ReactBrowserWorld.ts +41 -0
  54. package/src/frameworks/SvelteBrowserWorld.ts +15 -0
  55. package/src/frameworks/VueBrowserWorld.ts +23 -0
  56. package/src/frameworks/react.ts +4 -0
  57. package/src/frameworks/svelte.ts +4 -0
  58. package/src/frameworks/vue.ts +4 -0
  59. package/src/outcomes.steps.ts +190 -0
  60. package/tests/react/Hello.tsx +23 -0
  61. package/tests/react/react.feature +15 -0
  62. package/tests/svelte/Hello.svelte +31 -0
  63. package/tests/svelte/svelte.feature +16 -0
  64. package/tests/vue/Hello.vue +31 -0
  65. package/tests/vue/vue.feature +16 -0
  66. package/tsconfig.json +17 -0
  67. package/vite.config.ts +8 -0
  68. package/vitest.workspace.ts +95 -0
  69. package/world.ts +7 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # @quickpickle/vitest-browser
2
+
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 02bcadf: added react and vue for the browser module
8
+ - b1217d0: Initial functionality is working.
9
+ - Updated dependencies [2e7530d]
10
+ - Updated dependencies [094f7dd]
11
+ - Updated dependencies [7ad035c]
12
+ - Updated dependencies [1cf8cca]
13
+ - Updated dependencies [ab52cf6]
14
+ - Updated dependencies [1162c84]
15
+ - quickpickle@1.7.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 David Hunt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,4 @@
1
+ # Vitest: Browser Mode
2
+
3
+ This is the library for using Vitest with browser mode for testing components.
4
+
@@ -0,0 +1,179 @@
1
+ 'use strict';
2
+
3
+ var quickpickle = require('quickpickle');
4
+ var defaultsDeep = require('lodash/defaultsDeep');
5
+
6
+ const defaultVitestWorldConfig = {
7
+ componentDir: '', // directory in which components are kept, relative to project root
8
+ screenshotDir: 'screenshots', // directory in which to save screenshots, relative to project root (default: "screenshots")
9
+ screenshotOptions: {}, // options for the default screenshot comparisons
10
+ };
11
+ class VitestBrowserWorld extends quickpickle.QuickPickleWorld {
12
+ constructor(context, info) {
13
+ info = defaultsDeep(info || {}, { config: { worldConfig: defaultVitestWorldConfig } });
14
+ super(context, info);
15
+ if (!info.config.worldConfig.screenshotDir && info.config.worldConfig?.screenshotOptions?.customSnapshotsDir) {
16
+ this.info.config.worldConfig.screenshotDir = info.config.worldConfig.screenshotOptions.customSnapshotsDir;
17
+ }
18
+ this.renderFn = () => { };
19
+ this.cleanupFn = () => { };
20
+ }
21
+ async init() {
22
+ let browserContext = await import('@vitest/browser/context');
23
+ this.page = browserContext.page;
24
+ this.userEvent = browserContext.userEvent;
25
+ }
26
+ async render(name, props, renderOptions) {
27
+ let component = typeof name === 'string'
28
+ ? await import(`${this.projectRoot}/${this.worldConfig.componentDir}/${name}`.replace(/\/+/g, '/') /* @vite-ignore */)
29
+ : name;
30
+ await this.renderFn(component, props, renderOptions);
31
+ }
32
+ ;
33
+ async cleanup() {
34
+ await this.cleanupFn();
35
+ }
36
+ sanitizeFilepath(filepath) {
37
+ return filepath.replace(/\/\/+/g, '/').replace(/\/[\.~]+\//g, '/');
38
+ }
39
+ get screenshotDir() {
40
+ return this.sanitizeFilepath(`${this.projectRoot}/${this.worldConfig.screenshotDir}`);
41
+ }
42
+ get screenshotFilename() {
43
+ return `${this.toString().replace(/^.+?Feature: /, '').replace(' ' + this.info.step, '')}.png`;
44
+ }
45
+ /**
46
+ * Gets a locator based on a certain logic
47
+ * @example getLocator(page, 'Cancel', 'button') => page.getByRole('button', { name: 'Cancel' })
48
+ * @example getLocator(page, 'Search', 'input') => page.getByLabel('Search').or(page.getByPlaceholder('Search'))
49
+ * @example getLocator(page, 'ul.fourteen-points li', 'element', 'Open covenants of peace') => page.locator('ul.fourteen-points li').filter({ hasText: 'Open covenants of peace' })
50
+ *
51
+ * @param el The locator or page inside which to get a new locator
52
+ * @param identifier The value, label, placeholder, or css selector, depending on role
53
+ * @param role An ARIA role, "input", or "element"
54
+ * @param text Optional text to match inside the locator
55
+ * @returns Promise<void>
56
+ */
57
+ getLocator(el, identifier, role, text = null) {
58
+ let locator;
59
+ if (role === 'element')
60
+ throw new Error('Using "element" for CSS selectors is not yet supported; use an aria role or "input" instead.');
61
+ else if (role === 'input')
62
+ locator = el.getByLabelText(identifier).or(el.getByPlaceholder(identifier));
63
+ else
64
+ locator = el.getByRole(role, { name: identifier });
65
+ if (text && role !== 'input')
66
+ return locator.filter({ hasText: text });
67
+ return locator;
68
+ }
69
+ /**
70
+ * Sets a value on a form element based on its type (select, checkbox/radio, or other input)
71
+ * @example setValue(locator, "Option 1, Option 2") => Selects multiple options in a select element
72
+ * @example setValue(locator, "true") => Checks a checkbox/radio button
73
+ * @example setValue(locator, "false") => Unchecks a checkbox/radio button
74
+ * @example setValue(locator, "Some text") => Fills a text input with "Some text"
75
+ *
76
+ * @param locator The Playwright locator for the form element
77
+ * @param value The value to set - can be string or other value type
78
+ * @returns Promise<void>
79
+ */
80
+ async setValue(locator, value) {
81
+ let el = await locator.element();
82
+ let tag = el.tagName.toLowerCase();
83
+ if (!tag)
84
+ throw new Error(`Could not find element with locator: ${locator.toString()}`);
85
+ if (tag === 'select') {
86
+ let values = value.split(/\s*(?<!\\),\s*/).map((v) => v.replace(/\\,/g, ','));
87
+ await locator.selectOptions(values);
88
+ }
89
+ else if (isCheckboxOrRadio(el)) {
90
+ let check = !(['false', 'no', 'unchecked', '', 'null', 'undefined', '0'].includes(value.toString().toLowerCase()));
91
+ if (check)
92
+ el.checked = true;
93
+ else
94
+ el.checked = false;
95
+ }
96
+ else {
97
+ await locator.fill(value);
98
+ }
99
+ }
100
+ /**
101
+ * Scrolls the mouse wheel in a specified direction by a given number of pixels
102
+ * @example scroll("down", 100) => Scrolls down 100 pixels
103
+ * @example scroll("up", 50) => Scrolls up 50 pixels
104
+ * @example scroll("left", 200) => Scrolls left 200 pixels
105
+ * @example scroll("right") => Scrolls right using default 100 pixels
106
+ *
107
+ * @param direction The direction to scroll: "up", "down", "left", or "right"
108
+ * @param px The number of pixels to scroll (defaults to 100)
109
+ * @returns Promise<void>
110
+ */
111
+ async scroll(locator, direction, px = 100) {
112
+ let horiz = direction.includes('t');
113
+ let el = await locator.element();
114
+ if (horiz)
115
+ await el.scrollBy(direction === 'right' ? px : -px, 0);
116
+ else
117
+ await el.scrollBy(0, direction === 'down' ? px : -px);
118
+ }
119
+ /**
120
+ * A helper function for parsing text on a page or in an element.
121
+ * Can be used to check for the presence OR absence of visible OR hidden text.
122
+ * Examples:
123
+ * @example expectText(locator, 'text', true, true) // expect that a locator with the text is visible (and there may be hidden ones)
124
+ * @example expectText(locator, 'text', false, true) // expect that NO locator with the text is visible (but there may be hidden ones)
125
+ * @example expectText(locator, 'text', true, false) // expect that a HIDDEN locator with the text IS FOUND on the page (but there may be visible ones)
126
+ * @example expectText(locator, 'text', false, false) // expect that NO hidden locator with the text is found on the page (but there may be visible ones)
127
+ *
128
+ * @param locator the locator to check
129
+ * @param text the text to be found
130
+ * @param toBePresent whether a locator with the text should be present
131
+ * @param toBeVisible whether the locator with the text should be visible
132
+ * @returns void
133
+ */
134
+ async expectText(locator, text, toBePresent = true, toBeVisible = true) {
135
+ try {
136
+ await this.expectElement(locator.getByText(text), toBePresent, toBeVisible);
137
+ }
138
+ catch (e) {
139
+ let message = `The${toBeVisible ? '' : ' hidden'} text "${text}" was unexpectedly ${toBePresent ? 'not present' : 'present'}.`;
140
+ throw new Error(message);
141
+ }
142
+ }
143
+ /**
144
+ * A helper function for parsing elements on a page or in an element.
145
+ * Can be used to check for the presence OR absence of visible OR hidden elements.
146
+ * Examples:
147
+ * @example expectElement(locator, true) // expect that an element is visible (and there may be hidden ones)
148
+ * @example expectElement(locator, false) // expect that NO element is visible (but there may be hidden ones)
149
+ * @example expectElement(locator, true, false) // expect that a HIDDEN element IS FOUND on the page (but there may be visible ones)
150
+ * @example expectElement(locator, false, false) // expect that NO hidden element is found on the page (but there may be visible ones)
151
+ *
152
+ * @param locator the locator to check
153
+ * @param toBePresent whether an element should be present
154
+ * @param toBeVisible whether the element should be visible
155
+ */
156
+ async expectElement(locator, toBePresent = true, toBeVisible = true) {
157
+ let allElements = await locator.elements();
158
+ let matchingElements = allElements.filter(el => toBeVisible === el.checkVisibility({ opacityProperty: true, visibilityProperty: true }));
159
+ if (toBePresent === (matchingElements.length === 0))
160
+ throw new Error(`The${toBeVisible ? '' : ' hidden'} element "${locator}" was unexpectedly ${toBePresent ? 'not present' : 'present'}.`);
161
+ }
162
+ /**
163
+ * Waits for a certain amount of time
164
+ * @param ms number
165
+ */
166
+ async waitForTimeout(ms) {
167
+ await new Promise(r => setTimeout(r, ms));
168
+ }
169
+ }
170
+ function isCheckboxOrRadio(el) {
171
+ return el.type === 'checkbox' || el.type === 'radio';
172
+ }
173
+ quickpickle.Before(async (world) => {
174
+ await world.cleanup();
175
+ });
176
+
177
+ exports.VitestBrowserWorld = VitestBrowserWorld;
178
+ exports.defaultVitestWorldConfig = defaultVitestWorldConfig;
179
+ //# sourceMappingURL=VitestBrowserWorld.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VitestBrowserWorld.cjs","sources":["../src/VitestBrowserWorld.ts"],"sourcesContent":[null],"names":["QuickPickleWorld","Before"],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import { QuickPickleWorld, QuickPickleWorldInterface } from 'quickpickle';
2
+ import type { BrowserPage, Locator, UserEvent, ScreenshotOptions } from '@vitest/browser/context';
3
+ import type { TestContext } from 'vitest';
4
+ import { InfoConstructor } from 'quickpickle/dist/world';
5
+ export type VitestWorldConfig = {
6
+ componentDir?: string;
7
+ screenshotDir?: string;
8
+ screenshotOptions?: Partial<ScreenshotOptions>;
9
+ };
10
+ export declare const defaultVitestWorldConfig: VitestWorldConfig;
11
+ export type VitestBrowserWorldInterface = QuickPickleWorldInterface & {
12
+ render: (name: string | any, props?: any, renderOptions?: any) => Promise<void>;
13
+ renderFn: (component: any, props?: any, renderOptions?: any) => void | Promise<void>;
14
+ cleanup: () => Promise<void>;
15
+ cleanupFn: () => void | Promise<void>;
16
+ page: BrowserPage;
17
+ userEvent: UserEvent;
18
+ };
19
+ export declare class VitestBrowserWorld extends QuickPickleWorld implements VitestBrowserWorldInterface {
20
+ renderFn: (component: any, props: any, renderOptions: any) => void;
21
+ cleanupFn: () => void;
22
+ page: BrowserPage;
23
+ userEvent: UserEvent;
24
+ constructor(context: TestContext, info: InfoConstructor);
25
+ init(): Promise<void>;
26
+ render(name: string | any, props?: any, renderOptions?: any): Promise<void>;
27
+ cleanup(): Promise<void>;
28
+ sanitizeFilepath(filepath: string): string;
29
+ get screenshotDir(): string;
30
+ get screenshotFilename(): string;
31
+ /**
32
+ * Gets a locator based on a certain logic
33
+ * @example getLocator(page, 'Cancel', 'button') => page.getByRole('button', { name: 'Cancel' })
34
+ * @example getLocator(page, 'Search', 'input') => page.getByLabel('Search').or(page.getByPlaceholder('Search'))
35
+ * @example getLocator(page, 'ul.fourteen-points li', 'element', 'Open covenants of peace') => page.locator('ul.fourteen-points li').filter({ hasText: 'Open covenants of peace' })
36
+ *
37
+ * @param el The locator or page inside which to get a new locator
38
+ * @param identifier The value, label, placeholder, or css selector, depending on role
39
+ * @param role An ARIA role, "input", or "element"
40
+ * @param text Optional text to match inside the locator
41
+ * @returns Promise<void>
42
+ */
43
+ getLocator(el: Locator | BrowserPage, identifier: string, role: string | 'element' | 'input', text?: string | null): Locator;
44
+ /**
45
+ * Sets a value on a form element based on its type (select, checkbox/radio, or other input)
46
+ * @example setValue(locator, "Option 1, Option 2") => Selects multiple options in a select element
47
+ * @example setValue(locator, "true") => Checks a checkbox/radio button
48
+ * @example setValue(locator, "false") => Unchecks a checkbox/radio button
49
+ * @example setValue(locator, "Some text") => Fills a text input with "Some text"
50
+ *
51
+ * @param locator The Playwright locator for the form element
52
+ * @param value The value to set - can be string or other value type
53
+ * @returns Promise<void>
54
+ */
55
+ setValue(locator: Locator, value: string | any): Promise<void>;
56
+ /**
57
+ * Scrolls the mouse wheel in a specified direction by a given number of pixels
58
+ * @example scroll("down", 100) => Scrolls down 100 pixels
59
+ * @example scroll("up", 50) => Scrolls up 50 pixels
60
+ * @example scroll("left", 200) => Scrolls left 200 pixels
61
+ * @example scroll("right") => Scrolls right using default 100 pixels
62
+ *
63
+ * @param direction The direction to scroll: "up", "down", "left", or "right"
64
+ * @param px The number of pixels to scroll (defaults to 100)
65
+ * @returns Promise<void>
66
+ */
67
+ scroll(locator: Locator, direction: "up" | "down" | "left" | "right", px?: number): Promise<void>;
68
+ /**
69
+ * A helper function for parsing text on a page or in an element.
70
+ * Can be used to check for the presence OR absence of visible OR hidden text.
71
+ * Examples:
72
+ * @example expectText(locator, 'text', true, true) // expect that a locator with the text is visible (and there may be hidden ones)
73
+ * @example expectText(locator, 'text', false, true) // expect that NO locator with the text is visible (but there may be hidden ones)
74
+ * @example expectText(locator, 'text', true, false) // expect that a HIDDEN locator with the text IS FOUND on the page (but there may be visible ones)
75
+ * @example expectText(locator, 'text', false, false) // expect that NO hidden locator with the text is found on the page (but there may be visible ones)
76
+ *
77
+ * @param locator the locator to check
78
+ * @param text the text to be found
79
+ * @param toBePresent whether a locator with the text should be present
80
+ * @param toBeVisible whether the locator with the text should be visible
81
+ * @returns void
82
+ */
83
+ expectText(locator: Locator | BrowserPage, text: string, toBePresent?: boolean, toBeVisible?: boolean): Promise<void>;
84
+ /**
85
+ * A helper function for parsing elements on a page or in an element.
86
+ * Can be used to check for the presence OR absence of visible OR hidden elements.
87
+ * Examples:
88
+ * @example expectElement(locator, true) // expect that an element is visible (and there may be hidden ones)
89
+ * @example expectElement(locator, false) // expect that NO element is visible (but there may be hidden ones)
90
+ * @example expectElement(locator, true, false) // expect that a HIDDEN element IS FOUND on the page (but there may be visible ones)
91
+ * @example expectElement(locator, false, false) // expect that NO hidden element is found on the page (but there may be visible ones)
92
+ *
93
+ * @param locator the locator to check
94
+ * @param toBePresent whether an element should be present
95
+ * @param toBeVisible whether the element should be visible
96
+ */
97
+ expectElement(locator: Locator, toBePresent?: boolean, toBeVisible?: boolean): Promise<void>;
98
+ /**
99
+ * Waits for a certain amount of time
100
+ * @param ms number
101
+ */
102
+ waitForTimeout(ms: number): Promise<void>;
103
+ }
@@ -0,0 +1,176 @@
1
+ import { Before, QuickPickleWorld } from 'quickpickle';
2
+ import { defaultsDeep } from 'lodash-es';
3
+
4
+ const defaultVitestWorldConfig = {
5
+ componentDir: '', // directory in which components are kept, relative to project root
6
+ screenshotDir: 'screenshots', // directory in which to save screenshots, relative to project root (default: "screenshots")
7
+ screenshotOptions: {}, // options for the default screenshot comparisons
8
+ };
9
+ class VitestBrowserWorld extends QuickPickleWorld {
10
+ constructor(context, info) {
11
+ info = defaultsDeep(info || {}, { config: { worldConfig: defaultVitestWorldConfig } });
12
+ super(context, info);
13
+ if (!info.config.worldConfig.screenshotDir && info.config.worldConfig?.screenshotOptions?.customSnapshotsDir) {
14
+ this.info.config.worldConfig.screenshotDir = info.config.worldConfig.screenshotOptions.customSnapshotsDir;
15
+ }
16
+ this.renderFn = () => { };
17
+ this.cleanupFn = () => { };
18
+ }
19
+ async init() {
20
+ let browserContext = await import('@vitest/browser/context');
21
+ this.page = browserContext.page;
22
+ this.userEvent = browserContext.userEvent;
23
+ }
24
+ async render(name, props, renderOptions) {
25
+ let component = typeof name === 'string'
26
+ ? await import(`${this.projectRoot}/${this.worldConfig.componentDir}/${name}`.replace(/\/+/g, '/') /* @vite-ignore */)
27
+ : name;
28
+ await this.renderFn(component, props, renderOptions);
29
+ }
30
+ ;
31
+ async cleanup() {
32
+ await this.cleanupFn();
33
+ }
34
+ sanitizeFilepath(filepath) {
35
+ return filepath.replace(/\/\/+/g, '/').replace(/\/[\.~]+\//g, '/');
36
+ }
37
+ get screenshotDir() {
38
+ return this.sanitizeFilepath(`${this.projectRoot}/${this.worldConfig.screenshotDir}`);
39
+ }
40
+ get screenshotFilename() {
41
+ return `${this.toString().replace(/^.+?Feature: /, '').replace(' ' + this.info.step, '')}.png`;
42
+ }
43
+ /**
44
+ * Gets a locator based on a certain logic
45
+ * @example getLocator(page, 'Cancel', 'button') => page.getByRole('button', { name: 'Cancel' })
46
+ * @example getLocator(page, 'Search', 'input') => page.getByLabel('Search').or(page.getByPlaceholder('Search'))
47
+ * @example getLocator(page, 'ul.fourteen-points li', 'element', 'Open covenants of peace') => page.locator('ul.fourteen-points li').filter({ hasText: 'Open covenants of peace' })
48
+ *
49
+ * @param el The locator or page inside which to get a new locator
50
+ * @param identifier The value, label, placeholder, or css selector, depending on role
51
+ * @param role An ARIA role, "input", or "element"
52
+ * @param text Optional text to match inside the locator
53
+ * @returns Promise<void>
54
+ */
55
+ getLocator(el, identifier, role, text = null) {
56
+ let locator;
57
+ if (role === 'element')
58
+ throw new Error('Using "element" for CSS selectors is not yet supported; use an aria role or "input" instead.');
59
+ else if (role === 'input')
60
+ locator = el.getByLabelText(identifier).or(el.getByPlaceholder(identifier));
61
+ else
62
+ locator = el.getByRole(role, { name: identifier });
63
+ if (text && role !== 'input')
64
+ return locator.filter({ hasText: text });
65
+ return locator;
66
+ }
67
+ /**
68
+ * Sets a value on a form element based on its type (select, checkbox/radio, or other input)
69
+ * @example setValue(locator, "Option 1, Option 2") => Selects multiple options in a select element
70
+ * @example setValue(locator, "true") => Checks a checkbox/radio button
71
+ * @example setValue(locator, "false") => Unchecks a checkbox/radio button
72
+ * @example setValue(locator, "Some text") => Fills a text input with "Some text"
73
+ *
74
+ * @param locator The Playwright locator for the form element
75
+ * @param value The value to set - can be string or other value type
76
+ * @returns Promise<void>
77
+ */
78
+ async setValue(locator, value) {
79
+ let el = await locator.element();
80
+ let tag = el.tagName.toLowerCase();
81
+ if (!tag)
82
+ throw new Error(`Could not find element with locator: ${locator.toString()}`);
83
+ if (tag === 'select') {
84
+ let values = value.split(/\s*(?<!\\),\s*/).map((v) => v.replace(/\\,/g, ','));
85
+ await locator.selectOptions(values);
86
+ }
87
+ else if (isCheckboxOrRadio(el)) {
88
+ let check = !(['false', 'no', 'unchecked', '', 'null', 'undefined', '0'].includes(value.toString().toLowerCase()));
89
+ if (check)
90
+ el.checked = true;
91
+ else
92
+ el.checked = false;
93
+ }
94
+ else {
95
+ await locator.fill(value);
96
+ }
97
+ }
98
+ /**
99
+ * Scrolls the mouse wheel in a specified direction by a given number of pixels
100
+ * @example scroll("down", 100) => Scrolls down 100 pixels
101
+ * @example scroll("up", 50) => Scrolls up 50 pixels
102
+ * @example scroll("left", 200) => Scrolls left 200 pixels
103
+ * @example scroll("right") => Scrolls right using default 100 pixels
104
+ *
105
+ * @param direction The direction to scroll: "up", "down", "left", or "right"
106
+ * @param px The number of pixels to scroll (defaults to 100)
107
+ * @returns Promise<void>
108
+ */
109
+ async scroll(locator, direction, px = 100) {
110
+ let horiz = direction.includes('t');
111
+ let el = await locator.element();
112
+ if (horiz)
113
+ await el.scrollBy(direction === 'right' ? px : -px, 0);
114
+ else
115
+ await el.scrollBy(0, direction === 'down' ? px : -px);
116
+ }
117
+ /**
118
+ * A helper function for parsing text on a page or in an element.
119
+ * Can be used to check for the presence OR absence of visible OR hidden text.
120
+ * Examples:
121
+ * @example expectText(locator, 'text', true, true) // expect that a locator with the text is visible (and there may be hidden ones)
122
+ * @example expectText(locator, 'text', false, true) // expect that NO locator with the text is visible (but there may be hidden ones)
123
+ * @example expectText(locator, 'text', true, false) // expect that a HIDDEN locator with the text IS FOUND on the page (but there may be visible ones)
124
+ * @example expectText(locator, 'text', false, false) // expect that NO hidden locator with the text is found on the page (but there may be visible ones)
125
+ *
126
+ * @param locator the locator to check
127
+ * @param text the text to be found
128
+ * @param toBePresent whether a locator with the text should be present
129
+ * @param toBeVisible whether the locator with the text should be visible
130
+ * @returns void
131
+ */
132
+ async expectText(locator, text, toBePresent = true, toBeVisible = true) {
133
+ try {
134
+ await this.expectElement(locator.getByText(text), toBePresent, toBeVisible);
135
+ }
136
+ catch (e) {
137
+ let message = `The${toBeVisible ? '' : ' hidden'} text "${text}" was unexpectedly ${toBePresent ? 'not present' : 'present'}.`;
138
+ throw new Error(message);
139
+ }
140
+ }
141
+ /**
142
+ * A helper function for parsing elements on a page or in an element.
143
+ * Can be used to check for the presence OR absence of visible OR hidden elements.
144
+ * Examples:
145
+ * @example expectElement(locator, true) // expect that an element is visible (and there may be hidden ones)
146
+ * @example expectElement(locator, false) // expect that NO element is visible (but there may be hidden ones)
147
+ * @example expectElement(locator, true, false) // expect that a HIDDEN element IS FOUND on the page (but there may be visible ones)
148
+ * @example expectElement(locator, false, false) // expect that NO hidden element is found on the page (but there may be visible ones)
149
+ *
150
+ * @param locator the locator to check
151
+ * @param toBePresent whether an element should be present
152
+ * @param toBeVisible whether the element should be visible
153
+ */
154
+ async expectElement(locator, toBePresent = true, toBeVisible = true) {
155
+ let allElements = await locator.elements();
156
+ let matchingElements = allElements.filter(el => toBeVisible === el.checkVisibility({ opacityProperty: true, visibilityProperty: true }));
157
+ if (toBePresent === (matchingElements.length === 0))
158
+ throw new Error(`The${toBeVisible ? '' : ' hidden'} element "${locator}" was unexpectedly ${toBePresent ? 'not present' : 'present'}.`);
159
+ }
160
+ /**
161
+ * Waits for a certain amount of time
162
+ * @param ms number
163
+ */
164
+ async waitForTimeout(ms) {
165
+ await new Promise(r => setTimeout(r, ms));
166
+ }
167
+ }
168
+ function isCheckboxOrRadio(el) {
169
+ return el.type === 'checkbox' || el.type === 'radio';
170
+ }
171
+ Before(async (world) => {
172
+ await world.cleanup();
173
+ });
174
+
175
+ export { VitestBrowserWorld, defaultVitestWorldConfig };
176
+ //# sourceMappingURL=VitestBrowserWorld.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VitestBrowserWorld.mjs","sources":["../src/VitestBrowserWorld.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}