@rimori/playwright-testing 0.3.5-next.2 → 0.3.5-next.3

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.
@@ -79,6 +79,19 @@ export declare class RimoriTestEnvironment {
79
79
  * Removes a one-time mock from the mocks array after it's been used.
80
80
  */
81
81
  private removeOneTimeMock;
82
+ /**
83
+ * Creates a wrapper around the Playwright Request object that provides backwards compatibility
84
+ * for matchers. The new rimori-client sends `messages` array instead of `instructions`,
85
+ * so this wrapper extracts the prompts from messages and provides them as `instructions`.
86
+ *
87
+ * The old API had a single `instructions` field which typically contained the user's specific
88
+ * instruction (what the AI should do). The new API splits this into:
89
+ * - systemPrompt (messages[0] with role='system'): High-level behavior instructions
90
+ * - userPrompt (messages[1] with role='user'): Specific task instruction
91
+ *
92
+ * For backwards compatibility, we concatenate all message contents into `instructions`.
93
+ */
94
+ private createBackwardsCompatibleRequest;
82
95
  private handleRoute;
83
96
  /**
84
97
  * Adds a supabase route to the supabase routes object.
@@ -216,21 +229,44 @@ export declare class RimoriTestEnvironment {
216
229
  triggerOnMainPanelAction: (payload: MainPanelAction) => Promise<void>;
217
230
  };
218
231
  readonly ai: {
232
+ /**
233
+ * Mocks a text response from the LLM endpoint.
234
+ * Since getText now uses streamObject internally with a { result: string } schema,
235
+ * the mock value should be the full response object.
236
+ *
237
+ * @param values - The response object to return. Should include { result: string } for getText calls.
238
+ * @param options - Optional mock options.
239
+ */
219
240
  mockGetText: (values: unknown, options?: MockOptions) => void;
220
241
  /**
221
242
  * Mocks a streaming text response from the LLM endpoint.
222
- * The text will be formatted as SSE (Server-Sent Events) to simulate streaming.
243
+ * The new rimori-client's getSteamedText uses streamObject internally with { result: string } schema,
244
+ * so the text is wrapped in a result object.
223
245
  *
224
246
  * **Note**: Due to Playwright's route.fulfill() requiring a complete response body,
225
247
  * all SSE chunks are sent at once (no delays). The client will still parse it as SSE correctly.
226
248
  *
227
- * @param text - The text to stream. Will be formatted as SSE chunks.
249
+ * @param text - The text to stream. Will be wrapped as { result: text } and formatted as SSE.
228
250
  * @param options - Optional mock options.
229
251
  */
230
252
  mockGetSteamedText: (text: string, options?: MockOptions) => void;
231
253
  mockGetVoice: (values: Buffer, options?: MockOptions) => void;
232
254
  mockGetTextFromVoice: (text: string, options?: MockOptions) => void;
255
+ /**
256
+ * Mocks an object response from the LLM endpoint.
257
+ * Since getObject now uses streamObject internally, this is a streaming response.
258
+ *
259
+ * @param value - The object to return from the LLM.
260
+ * @param options - Optional mock options.
261
+ */
233
262
  mockGetObject: (value: Record<string, unknown>, options?: MockOptions) => void;
263
+ /**
264
+ * Mocks a streaming object response from the LLM endpoint.
265
+ * Returns the object via SSE format with data: prefix.
266
+ *
267
+ * @param value - The object to stream from the LLM.
268
+ * @param options - Optional mock options.
269
+ */
234
270
  mockGetStreamedObject: (value: Record<string, unknown>, options?: MockOptions) => void;
235
271
  };
236
272
  /**
@@ -197,23 +197,31 @@ class RimoriTestEnvironment {
197
197
  },
198
198
  };
199
199
  this.ai = {
200
+ /**
201
+ * Mocks a text response from the LLM endpoint.
202
+ * Since getText now uses streamObject internally with a { result: string } schema,
203
+ * the mock value should be the full response object.
204
+ *
205
+ * @param values - The response object to return. Should include { result: string } for getText calls.
206
+ * @param options - Optional mock options.
207
+ */
200
208
  mockGetText: (values, options) => {
201
- console.log('Mocking get text for mockGetText', values, options);
202
- console.warn('mockGetText is not tested');
203
- this.addBackendRoute('/llm-text', values, options);
209
+ this.addBackendRoute('/ai/llm', values, { ...options, isStreaming: true });
204
210
  },
205
211
  /**
206
212
  * Mocks a streaming text response from the LLM endpoint.
207
- * The text will be formatted as SSE (Server-Sent Events) to simulate streaming.
213
+ * The new rimori-client's getSteamedText uses streamObject internally with { result: string } schema,
214
+ * so the text is wrapped in a result object.
208
215
  *
209
216
  * **Note**: Due to Playwright's route.fulfill() requiring a complete response body,
210
217
  * all SSE chunks are sent at once (no delays). The client will still parse it as SSE correctly.
211
218
  *
212
- * @param text - The text to stream. Will be formatted as SSE chunks.
219
+ * @param text - The text to stream. Will be wrapped as { result: text } and formatted as SSE.
213
220
  * @param options - Optional mock options.
214
221
  */
215
222
  mockGetSteamedText: (text, options) => {
216
- this.addBackendRoute('/ai/llm', text, { ...options, isStreaming: true });
223
+ // Wrap text in result object as the new client expects { result: string }
224
+ this.addBackendRoute('/ai/llm', { result: text }, { ...options, isStreaming: true });
217
225
  },
218
226
  mockGetVoice: (values, options) => {
219
227
  this.addBackendRoute('/voice/tts', values, options);
@@ -221,11 +229,25 @@ class RimoriTestEnvironment {
221
229
  mockGetTextFromVoice: (text, options) => {
222
230
  this.addBackendRoute('/voice/stt', text, options);
223
231
  },
232
+ /**
233
+ * Mocks an object response from the LLM endpoint.
234
+ * Since getObject now uses streamObject internally, this is a streaming response.
235
+ *
236
+ * @param value - The object to return from the LLM.
237
+ * @param options - Optional mock options.
238
+ */
224
239
  mockGetObject: (value, options) => {
225
- this.addBackendRoute('/ai/llm-object', value, { ...options, method: 'POST' });
240
+ this.addBackendRoute('/ai/llm', value, { ...options, isStreaming: true });
226
241
  },
242
+ /**
243
+ * Mocks a streaming object response from the LLM endpoint.
244
+ * Returns the object via SSE format with data: prefix.
245
+ *
246
+ * @param value - The object to stream from the LLM.
247
+ * @param options - Optional mock options.
248
+ */
227
249
  mockGetStreamedObject: (value, options) => {
228
- this.addBackendRoute('/ai/llm-object', value, { ...options, isStreaming: true });
250
+ this.addBackendRoute('/ai/llm', value, { ...options, isStreaming: true });
229
251
  },
230
252
  };
231
253
  /**
@@ -776,6 +798,53 @@ class RimoriTestEnvironment {
776
798
  mocks.splice(index, 1);
777
799
  }
778
800
  }
801
+ /**
802
+ * Creates a wrapper around the Playwright Request object that provides backwards compatibility
803
+ * for matchers. The new rimori-client sends `messages` array instead of `instructions`,
804
+ * so this wrapper extracts the prompts from messages and provides them as `instructions`.
805
+ *
806
+ * The old API had a single `instructions` field which typically contained the user's specific
807
+ * instruction (what the AI should do). The new API splits this into:
808
+ * - systemPrompt (messages[0] with role='system'): High-level behavior instructions
809
+ * - userPrompt (messages[1] with role='user'): Specific task instruction
810
+ *
811
+ * For backwards compatibility, we concatenate all message contents into `instructions`.
812
+ */
813
+ createBackwardsCompatibleRequest(originalRequest) {
814
+ // Create a proxy that intercepts postDataJSON calls
815
+ return new Proxy(originalRequest, {
816
+ get(target, prop) {
817
+ if (prop === 'postDataJSON') {
818
+ return () => {
819
+ try {
820
+ const body = target.postDataJSON();
821
+ if (body && body.messages && Array.isArray(body.messages) && !body.instructions) {
822
+ // Concatenate all message contents for backwards compatibility
823
+ // This allows matchers to check for text that might be in either system or user prompts
824
+ const allContent = body.messages
825
+ .map((m) => m.content || '')
826
+ .filter((content) => content.length > 0)
827
+ .join('\n');
828
+ if (allContent) {
829
+ return { ...body, instructions: allContent };
830
+ }
831
+ }
832
+ return body;
833
+ }
834
+ catch {
835
+ return null;
836
+ }
837
+ };
838
+ }
839
+ // For all other properties, return the original value bound to the target
840
+ const value = target[prop];
841
+ if (typeof value === 'function') {
842
+ return value.bind(target);
843
+ }
844
+ return value;
845
+ },
846
+ });
847
+ }
779
848
  async handleRoute(route, routes) {
780
849
  const request = route.request();
781
850
  const requestUrl = request.url();
@@ -789,6 +858,8 @@ class RimoriTestEnvironment {
789
858
  route.abort('not_found');
790
859
  return;
791
860
  }
861
+ // Create backwards-compatible request wrapper for matchers
862
+ const compatRequest = this.createBackwardsCompatibleRequest(request);
792
863
  // Find the first matching mock based on matcher function
793
864
  // Priority: mocks with matchers that match > mocks without matchers (as fallback)
794
865
  let matchingMock;
@@ -796,7 +867,8 @@ class RimoriTestEnvironment {
796
867
  for (const mock of mocks) {
797
868
  if (mock.options?.matcher) {
798
869
  try {
799
- if (mock.options.matcher(request)) {
870
+ // Use the backwards-compatible request wrapper for matchers
871
+ if (mock.options.matcher(compatRequest)) {
800
872
  matchingMock = mock;
801
873
  break;
802
874
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimori/playwright-testing",
3
- "version": "0.3.5-next.2",
3
+ "version": "0.3.5-next.3",
4
4
  "description": "Playwright testing utilities for Rimori plugins and workers",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -23,11 +23,11 @@
23
23
  },
24
24
  "peerDependencies": {
25
25
  "@playwright/test": "^1.40.0",
26
- "@rimori/client": "2.5.10-next.0"
26
+ "@rimori/client": "2.5.11-next.1"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@playwright/test": "^1.40.0",
30
- "@rimori/client": "2.5.10-next.0",
30
+ "@rimori/client": "2.5.11-next.1",
31
31
  "@types/node": "^20.12.7",
32
32
  "rimraf": "^5.0.7",
33
33
  "typescript": "^5.7.2"