@chrryai/waffles 1.1.78

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 ADDED
@@ -0,0 +1,235 @@
1
+ # ๐Ÿง‡ Waffles
2
+
3
+ **Production-ready Playwright testing utilities** โ€” Battle-tested helpers from [Vex](https://askvex.com)
4
+
5
+ ## ๐ŸŽฏ Why Waffles?
6
+
7
+ Waffles provides a collection of battle-tested Playwright utilities that make E2E testing delightful. Born from real-world production testing at Vex, these helpers solve common testing challenges.
8
+
9
+ ## โœจ Features
10
+
11
+ - ๐ŸŽญ **Playwright-first** - Built specifically for Playwright
12
+ - ๐Ÿงช **Production-tested** - Used in Vex's extensive test suite
13
+ - ๐Ÿ“ฆ **Zero config** - Works out of the box
14
+ - ๐ŸŽฏ **TypeScript** - Full type safety
15
+ - ๐Ÿš€ **Lightweight** - Minimal dependencies
16
+
17
+ ## ๐Ÿ“ฆ Installation
18
+
19
+ ```bash
20
+ npm install @askvex/waffles @playwright/test
21
+ ```
22
+
23
+ ## ๐Ÿš€ Quick Start
24
+
25
+ ```typescript
26
+ import { test, expect } from "@playwright/test"
27
+ import {
28
+ wait,
29
+ simulateInputPaste,
30
+ waitForElement,
31
+ generateTestEmail,
32
+ } from "@askvex/waffles"
33
+
34
+ test("chat interaction", async ({ page }) => {
35
+ await page.goto("https://yourapp.com")
36
+
37
+ // Wait for chat to load
38
+ await waitForElement(page, '[data-testid="chat-textarea"]')
39
+
40
+ // Simulate pasting text
41
+ await simulateInputPaste(page, "Hello, AI!")
42
+
43
+ // Wait for response
44
+ await wait(1000)
45
+
46
+ // Assert
47
+ await expect(page.locator(".message")).toBeVisible()
48
+ })
49
+ ```
50
+
51
+ ## ๐Ÿ“š API Reference
52
+
53
+ ### Timing Utilities
54
+
55
+ #### `wait(ms: number)`
56
+
57
+ Wait for a specified number of milliseconds.
58
+
59
+ ```typescript
60
+ await wait(1000) // Wait 1 second
61
+ ```
62
+
63
+ #### `waitForElement(page, selector, timeout?)`
64
+
65
+ Wait for an element to be visible.
66
+
67
+ ```typescript
68
+ await waitForElement(page, ".loading-spinner", 5000)
69
+ ```
70
+
71
+ #### `waitForElementToDisappear(page, selector, timeout?)`
72
+
73
+ Wait for an element to disappear.
74
+
75
+ ```typescript
76
+ await waitForElementToDisappear(page, ".loading-spinner")
77
+ ```
78
+
79
+ ### Input Simulation
80
+
81
+ #### `simulateInputPaste(page, text, selector?)`
82
+
83
+ Simulate pasting text into a textarea.
84
+
85
+ ```typescript
86
+ await simulateInputPaste(page, "Pasted content")
87
+ ```
88
+
89
+ #### `simulatePaste(page, text, buttonSelector?)`
90
+
91
+ Simulate pasting using clipboard API and clicking paste button.
92
+
93
+ ```typescript
94
+ await simulatePaste(page, "Clipboard content")
95
+ ```
96
+
97
+ ### Navigation
98
+
99
+ #### `getURL(options)`
100
+
101
+ Generate a URL with optional fingerprint for testing.
102
+
103
+ ```typescript
104
+ const url = getURL({
105
+ baseURL: "https://app.com",
106
+ path: "/chat",
107
+ isMember: true,
108
+ memberFingerprint: "abc-123",
109
+ })
110
+ ```
111
+
112
+ #### `scrollToBottom(page)`
113
+
114
+ Scroll to the bottom of the page.
115
+
116
+ ```typescript
117
+ await scrollToBottom(page)
118
+ ```
119
+
120
+ ### Utilities
121
+
122
+ #### `capitalizeFirstLetter(str: string)`
123
+
124
+ Capitalize the first letter of a string.
125
+
126
+ ```typescript
127
+ capitalizeFirstLetter("hello") // "Hello"
128
+ ```
129
+
130
+ #### `generateTestEmail(prefix?)`
131
+
132
+ Generate a unique test email.
133
+
134
+ ```typescript
135
+ const email = generateTestEmail("user") // user-1234567890-abc123@test.com
136
+ ```
137
+
138
+ #### `generateTestPassword(length?)`
139
+
140
+ Generate a random password for testing.
141
+
142
+ ```typescript
143
+ const password = generateTestPassword(16)
144
+ ```
145
+
146
+ ### Cleanup
147
+
148
+ #### `clearLocalStorage(page)`
149
+
150
+ Clear browser local storage.
151
+
152
+ ```typescript
153
+ await clearLocalStorage(page)
154
+ ```
155
+
156
+ #### `clearCookies(page)`
157
+
158
+ Clear browser cookies.
159
+
160
+ ```typescript
161
+ await clearCookies(page)
162
+ ```
163
+
164
+ ### Screenshots
165
+
166
+ #### `takeScreenshot(page, name, fullPage?)`
167
+
168
+ Take a screenshot with a custom name.
169
+
170
+ ```typescript
171
+ await takeScreenshot(page, "error-state", true)
172
+ ```
173
+
174
+ ## ๐ŸŽจ Real-World Examples
175
+
176
+ ### Testing Chat Flow
177
+
178
+ ```typescript
179
+ import { test } from "@playwright/test"
180
+ import { simulateInputPaste, waitForElement, wait } from "@askvex/waffles"
181
+
182
+ test("complete chat interaction", async ({ page }) => {
183
+ await page.goto("https://app.com/chat")
184
+
185
+ // Wait for chat to be ready
186
+ await waitForElement(page, '[data-testid="chat-textarea"]')
187
+
188
+ // Send message
189
+ await simulateInputPaste(page, "What's the weather?")
190
+ await page.click('[data-testid="send-button"]')
191
+
192
+ // Wait for AI response
193
+ await wait(2000)
194
+ await waitForElement(page, ".ai-message")
195
+ })
196
+ ```
197
+
198
+ ### Testing Authentication
199
+
200
+ ```typescript
201
+ import { test } from "@playwright/test"
202
+ import { generateTestEmail, generateTestPassword, wait } from "@askvex/waffles"
203
+
204
+ test("user registration", async ({ page }) => {
205
+ const email = generateTestEmail("newuser")
206
+ const password = generateTestPassword()
207
+
208
+ await page.goto("https://app.com/signup")
209
+ await page.fill('[name="email"]', email)
210
+ await page.fill('[name="password"]', password)
211
+ await page.click('button[type="submit"]')
212
+
213
+ await wait(1000)
214
+ await expect(page).toHaveURL(/dashboard/)
215
+ })
216
+ ```
217
+
218
+ ## ๐Ÿค Contributing
219
+
220
+ We welcome contributions! Waffles is extracted from Vex's production test suite, and we're always improving it.
221
+
222
+ ## ๐Ÿ“„ License
223
+
224
+ MIT ยฉ [AskVex](https://askvex.com)
225
+
226
+ ## ๐Ÿ”— Links
227
+
228
+ - [GitHub](https://github.com/askvex/waffles)
229
+ - [npm](https://npmjs.com/package/@askvex/waffles)
230
+ - [Issues](https://github.com/askvex/waffles/issues)
231
+ - [Vex - Powered by Waffles](https://askvex.com)
232
+
233
+ ---
234
+
235
+ **Built with โค๏ธ by the Vex team**
@@ -0,0 +1,107 @@
1
+ import { Page, Browser } from '@playwright/test';
2
+ import { Page as Page$1 } from 'playwright';
3
+
4
+ declare const TEST_GUEST_FINGERPRINTS: string[];
5
+ declare const TEST_MEMBER_FINGERPRINTS: string[];
6
+ declare const TEST_MEMBER_EMAILS: string[];
7
+ declare const VEX_TEST_EMAIL: string;
8
+ declare const VEX_TEST_PASSWORD: string;
9
+ declare const VEX_TEST_FINGERPRINT: string | undefined;
10
+ declare const VEX_TEST_EMAIL_2: string;
11
+ declare const VEX_TEST_PASSWORD_2: string;
12
+ declare const VEX_TEST_FINGERPRINT_2: string | undefined;
13
+ declare const VEX_TEST_EMAIL_3: string;
14
+ declare const VEX_TEST_PASSWORD_3: string;
15
+ declare const VEX_TEST_FINGERPRINT_3: string | undefined;
16
+ declare const TEST_URL: string;
17
+ declare const LIVE_URL = "https://askvex.com";
18
+ declare const wait: (ms: number) => Promise<unknown>;
19
+ declare const isCI: string | undefined;
20
+ declare const getURL: ({ isLive, isMember, path, fingerprint, }?: {
21
+ isLive: boolean;
22
+ isMember?: boolean;
23
+ path?: string;
24
+ fingerprint?: string;
25
+ }) => string;
26
+ declare const simulateInputPaste: (page: Page, text: string) => Promise<void>;
27
+ declare const simulatePaste: (page: Page, text: string) => Promise<void>;
28
+ declare function capitalizeFirstLetter(val: string): string;
29
+
30
+ type modelName = "chatGPT" | "claude" | "deepSeek" | "gemini" | "flux";
31
+ declare const chat: ({ artifacts, page, isMember, isSubscriber, instruction, prompts, agentMessageTimeout, isNewChat, isLiveTest, threadId, creditsConsumed, bookmark, }: {
32
+ isSubscriber?: boolean;
33
+ artifacts?: {
34
+ text?: number;
35
+ paste?: number;
36
+ pdf?: number;
37
+ };
38
+ page: Page;
39
+ isMember?: boolean;
40
+ instruction?: string;
41
+ prompts?: {
42
+ debateAgent?: modelName;
43
+ stop?: boolean;
44
+ text: string;
45
+ instruction?: string;
46
+ deleteMessage?: boolean;
47
+ deleteAgentMessage?: boolean;
48
+ model?: modelName;
49
+ agentMessageTimeout?: number;
50
+ shouldFail?: boolean;
51
+ like?: boolean;
52
+ delete?: boolean;
53
+ webSearch?: boolean;
54
+ image?: number;
55
+ video?: number;
56
+ audio?: number;
57
+ paste?: number;
58
+ pdf?: number;
59
+ mix?: {
60
+ image?: number;
61
+ video?: number;
62
+ audio?: number;
63
+ paste?: number;
64
+ pdf?: number;
65
+ };
66
+ }[];
67
+ agentMessageTimeout?: number;
68
+ isNewChat?: boolean;
69
+ isLiveTest?: boolean;
70
+ threadId?: string;
71
+ creditsConsumed?: number;
72
+ bookmark?: boolean;
73
+ }) => Promise<void>;
74
+
75
+ declare function collaboration({ page, isLive, isMember, browser, withShareLink, fingerprint, collaborate, }: {
76
+ page: Page$1;
77
+ isLive?: boolean;
78
+ isMember?: boolean;
79
+ browser: Browser;
80
+ withShareLink?: boolean;
81
+ collaborate?: string;
82
+ fingerprint?: string;
83
+ }): Promise<void>;
84
+
85
+ declare const limit: ({ page, isMember, isSubscriber, }: {
86
+ page: Page;
87
+ isMember?: boolean;
88
+ isSubscriber?: boolean;
89
+ }) => Promise<void>;
90
+
91
+ declare const signIn: ({ page, isOpened, signOut, register, email, password, }: {
92
+ page: Page;
93
+ isOpened?: boolean;
94
+ signOut?: boolean;
95
+ register?: boolean;
96
+ email?: string;
97
+ password?: string;
98
+ }) => Promise<void>;
99
+
100
+ declare const thread: ({ page, isMember, bookmark, createChat, }: {
101
+ page: Page;
102
+ isMember?: boolean;
103
+ createChat?: boolean;
104
+ bookmark?: boolean;
105
+ }) => Promise<void>;
106
+
107
+ export { LIVE_URL, TEST_GUEST_FINGERPRINTS, TEST_MEMBER_EMAILS, TEST_MEMBER_FINGERPRINTS, TEST_URL, VEX_TEST_EMAIL, VEX_TEST_EMAIL_2, VEX_TEST_EMAIL_3, VEX_TEST_FINGERPRINT, VEX_TEST_FINGERPRINT_2, VEX_TEST_FINGERPRINT_3, VEX_TEST_PASSWORD, VEX_TEST_PASSWORD_2, VEX_TEST_PASSWORD_3, capitalizeFirstLetter, chat, collaboration, getURL, isCI, limit, type modelName, signIn, simulateInputPaste, simulatePaste, thread, wait };
@@ -0,0 +1,107 @@
1
+ import { Page, Browser } from '@playwright/test';
2
+ import { Page as Page$1 } from 'playwright';
3
+
4
+ declare const TEST_GUEST_FINGERPRINTS: string[];
5
+ declare const TEST_MEMBER_FINGERPRINTS: string[];
6
+ declare const TEST_MEMBER_EMAILS: string[];
7
+ declare const VEX_TEST_EMAIL: string;
8
+ declare const VEX_TEST_PASSWORD: string;
9
+ declare const VEX_TEST_FINGERPRINT: string | undefined;
10
+ declare const VEX_TEST_EMAIL_2: string;
11
+ declare const VEX_TEST_PASSWORD_2: string;
12
+ declare const VEX_TEST_FINGERPRINT_2: string | undefined;
13
+ declare const VEX_TEST_EMAIL_3: string;
14
+ declare const VEX_TEST_PASSWORD_3: string;
15
+ declare const VEX_TEST_FINGERPRINT_3: string | undefined;
16
+ declare const TEST_URL: string;
17
+ declare const LIVE_URL = "https://askvex.com";
18
+ declare const wait: (ms: number) => Promise<unknown>;
19
+ declare const isCI: string | undefined;
20
+ declare const getURL: ({ isLive, isMember, path, fingerprint, }?: {
21
+ isLive: boolean;
22
+ isMember?: boolean;
23
+ path?: string;
24
+ fingerprint?: string;
25
+ }) => string;
26
+ declare const simulateInputPaste: (page: Page, text: string) => Promise<void>;
27
+ declare const simulatePaste: (page: Page, text: string) => Promise<void>;
28
+ declare function capitalizeFirstLetter(val: string): string;
29
+
30
+ type modelName = "chatGPT" | "claude" | "deepSeek" | "gemini" | "flux";
31
+ declare const chat: ({ artifacts, page, isMember, isSubscriber, instruction, prompts, agentMessageTimeout, isNewChat, isLiveTest, threadId, creditsConsumed, bookmark, }: {
32
+ isSubscriber?: boolean;
33
+ artifacts?: {
34
+ text?: number;
35
+ paste?: number;
36
+ pdf?: number;
37
+ };
38
+ page: Page;
39
+ isMember?: boolean;
40
+ instruction?: string;
41
+ prompts?: {
42
+ debateAgent?: modelName;
43
+ stop?: boolean;
44
+ text: string;
45
+ instruction?: string;
46
+ deleteMessage?: boolean;
47
+ deleteAgentMessage?: boolean;
48
+ model?: modelName;
49
+ agentMessageTimeout?: number;
50
+ shouldFail?: boolean;
51
+ like?: boolean;
52
+ delete?: boolean;
53
+ webSearch?: boolean;
54
+ image?: number;
55
+ video?: number;
56
+ audio?: number;
57
+ paste?: number;
58
+ pdf?: number;
59
+ mix?: {
60
+ image?: number;
61
+ video?: number;
62
+ audio?: number;
63
+ paste?: number;
64
+ pdf?: number;
65
+ };
66
+ }[];
67
+ agentMessageTimeout?: number;
68
+ isNewChat?: boolean;
69
+ isLiveTest?: boolean;
70
+ threadId?: string;
71
+ creditsConsumed?: number;
72
+ bookmark?: boolean;
73
+ }) => Promise<void>;
74
+
75
+ declare function collaboration({ page, isLive, isMember, browser, withShareLink, fingerprint, collaborate, }: {
76
+ page: Page$1;
77
+ isLive?: boolean;
78
+ isMember?: boolean;
79
+ browser: Browser;
80
+ withShareLink?: boolean;
81
+ collaborate?: string;
82
+ fingerprint?: string;
83
+ }): Promise<void>;
84
+
85
+ declare const limit: ({ page, isMember, isSubscriber, }: {
86
+ page: Page;
87
+ isMember?: boolean;
88
+ isSubscriber?: boolean;
89
+ }) => Promise<void>;
90
+
91
+ declare const signIn: ({ page, isOpened, signOut, register, email, password, }: {
92
+ page: Page;
93
+ isOpened?: boolean;
94
+ signOut?: boolean;
95
+ register?: boolean;
96
+ email?: string;
97
+ password?: string;
98
+ }) => Promise<void>;
99
+
100
+ declare const thread: ({ page, isMember, bookmark, createChat, }: {
101
+ page: Page;
102
+ isMember?: boolean;
103
+ createChat?: boolean;
104
+ bookmark?: boolean;
105
+ }) => Promise<void>;
106
+
107
+ export { LIVE_URL, TEST_GUEST_FINGERPRINTS, TEST_MEMBER_EMAILS, TEST_MEMBER_FINGERPRINTS, TEST_URL, VEX_TEST_EMAIL, VEX_TEST_EMAIL_2, VEX_TEST_EMAIL_3, VEX_TEST_FINGERPRINT, VEX_TEST_FINGERPRINT_2, VEX_TEST_FINGERPRINT_3, VEX_TEST_PASSWORD, VEX_TEST_PASSWORD_2, VEX_TEST_PASSWORD_3, capitalizeFirstLetter, chat, collaboration, getURL, isCI, limit, type modelName, signIn, simulateInputPaste, simulatePaste, thread, wait };