@arcadialdev/arcality 2.4.29 → 2.4.30

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 (80) hide show
  1. package/package.json +3 -4
  2. package/src/arcalityClient.mjs +2 -1
  3. package/.agents/skills/e2e-testing-expert/SKILL.md +0 -28
  4. package/.agents/skills/frontend-design/LICENSE.txt +0 -177
  5. package/.agents/skills/frontend-design/SKILL.md +0 -42
  6. package/.agents/skills/nodejs-backend-patterns/SKILL.md +0 -639
  7. package/.agents/skills/nodejs-backend-patterns/references/advanced-patterns.md +0 -430
  8. package/.agents/skills/playwright-best-practices/LICENSE.md +0 -7
  9. package/.agents/skills/playwright-best-practices/README.md +0 -147
  10. package/.agents/skills/playwright-best-practices/SKILL.md +0 -303
  11. package/.agents/skills/playwright-best-practices/advanced/authentication-flows.md +0 -360
  12. package/.agents/skills/playwright-best-practices/advanced/authentication.md +0 -871
  13. package/.agents/skills/playwright-best-practices/advanced/clock-mocking.md +0 -364
  14. package/.agents/skills/playwright-best-practices/advanced/mobile-testing.md +0 -409
  15. package/.agents/skills/playwright-best-practices/advanced/multi-context.md +0 -288
  16. package/.agents/skills/playwright-best-practices/advanced/multi-user.md +0 -393
  17. package/.agents/skills/playwright-best-practices/advanced/network-advanced.md +0 -452
  18. package/.agents/skills/playwright-best-practices/advanced/third-party.md +0 -464
  19. package/.agents/skills/playwright-best-practices/architecture/pom-vs-fixtures.md +0 -363
  20. package/.agents/skills/playwright-best-practices/architecture/test-architecture.md +0 -369
  21. package/.agents/skills/playwright-best-practices/architecture/when-to-mock.md +0 -383
  22. package/.agents/skills/playwright-best-practices/browser-apis/browser-apis.md +0 -391
  23. package/.agents/skills/playwright-best-practices/browser-apis/iframes.md +0 -403
  24. package/.agents/skills/playwright-best-practices/browser-apis/service-workers.md +0 -504
  25. package/.agents/skills/playwright-best-practices/browser-apis/websockets.md +0 -403
  26. package/.agents/skills/playwright-best-practices/core/annotations.md +0 -424
  27. package/.agents/skills/playwright-best-practices/core/assertions-waiting.md +0 -361
  28. package/.agents/skills/playwright-best-practices/core/configuration.md +0 -452
  29. package/.agents/skills/playwright-best-practices/core/fixtures-hooks.md +0 -417
  30. package/.agents/skills/playwright-best-practices/core/global-setup.md +0 -434
  31. package/.agents/skills/playwright-best-practices/core/locators.md +0 -242
  32. package/.agents/skills/playwright-best-practices/core/page-object-model.md +0 -315
  33. package/.agents/skills/playwright-best-practices/core/projects-dependencies.md +0 -453
  34. package/.agents/skills/playwright-best-practices/core/test-data.md +0 -492
  35. package/.agents/skills/playwright-best-practices/core/test-suite-structure.md +0 -361
  36. package/.agents/skills/playwright-best-practices/core/test-tags.md +0 -298
  37. package/.agents/skills/playwright-best-practices/debugging/console-errors.md +0 -420
  38. package/.agents/skills/playwright-best-practices/debugging/debugging.md +0 -504
  39. package/.agents/skills/playwright-best-practices/debugging/error-testing.md +0 -360
  40. package/.agents/skills/playwright-best-practices/debugging/flaky-tests.md +0 -496
  41. package/.agents/skills/playwright-best-practices/frameworks/angular.md +0 -530
  42. package/.agents/skills/playwright-best-practices/frameworks/nextjs.md +0 -469
  43. package/.agents/skills/playwright-best-practices/frameworks/react.md +0 -531
  44. package/.agents/skills/playwright-best-practices/frameworks/vue.md +0 -574
  45. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/ci-cd.md +0 -468
  46. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/docker.md +0 -283
  47. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/github-actions.md +0 -546
  48. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/gitlab.md +0 -397
  49. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/other-providers.md +0 -521
  50. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/parallel-sharding.md +0 -371
  51. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/performance.md +0 -453
  52. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/reporting.md +0 -424
  53. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/test-coverage.md +0 -497
  54. package/.agents/skills/playwright-best-practices/testing-patterns/accessibility.md +0 -359
  55. package/.agents/skills/playwright-best-practices/testing-patterns/api-testing.md +0 -719
  56. package/.agents/skills/playwright-best-practices/testing-patterns/browser-extensions.md +0 -506
  57. package/.agents/skills/playwright-best-practices/testing-patterns/canvas-webgl.md +0 -493
  58. package/.agents/skills/playwright-best-practices/testing-patterns/component-testing.md +0 -500
  59. package/.agents/skills/playwright-best-practices/testing-patterns/drag-drop.md +0 -576
  60. package/.agents/skills/playwright-best-practices/testing-patterns/electron.md +0 -509
  61. package/.agents/skills/playwright-best-practices/testing-patterns/file-operations.md +0 -377
  62. package/.agents/skills/playwright-best-practices/testing-patterns/file-upload-download.md +0 -562
  63. package/.agents/skills/playwright-best-practices/testing-patterns/forms-validation.md +0 -561
  64. package/.agents/skills/playwright-best-practices/testing-patterns/graphql-testing.md +0 -331
  65. package/.agents/skills/playwright-best-practices/testing-patterns/i18n.md +0 -508
  66. package/.agents/skills/playwright-best-practices/testing-patterns/performance-testing.md +0 -476
  67. package/.agents/skills/playwright-best-practices/testing-patterns/security-testing.md +0 -430
  68. package/.agents/skills/playwright-best-practices/testing-patterns/visual-regression.md +0 -634
  69. package/.agents/skills/security-qa/SKILL.md +0 -254
  70. package/public/ArcalityImagen.png +0 -0
  71. package/public/logo-arcadial-blanco.png +0 -0
  72. package/public/logo.png +0 -0
  73. package/tests/_helpers/ArcalityReporter.ts +0 -733
  74. package/tests/_helpers/agentic-runner.spec.ts +0 -783
  75. package/tests/_helpers/ai-agent-helper.ts +0 -1660
  76. package/tests/_helpers/discover-view.spec.ts +0 -238
  77. package/tests/_helpers/extract-view.spec.ts +0 -118
  78. package/tests/_helpers/qa-security-tools.ts +0 -265
  79. package/tests/_helpers/qa-tools.ts +0 -333
  80. package/tests/_helpers/smart-action.spec.ts +0 -1458
@@ -1,393 +0,0 @@
1
- # Multi-User & Collaboration Testing
2
-
3
- ## Table of Contents
4
-
5
- 1. [Multiple Browser Contexts](#multiple-browser-contexts)
6
- 2. [Real-Time Collaboration](#real-time-collaboration)
7
- 3. [Role-Based Testing](#role-based-testing)
8
- 4. [Concurrent Actions](#concurrent-actions)
9
- 5. [Chat & Messaging](#chat--messaging)
10
-
11
- ## Multiple Browser Contexts
12
-
13
- ### Two Users in Same Test
14
-
15
- ```typescript
16
- test("two users see each other's changes", async ({ browser }) => {
17
- // Create two isolated contexts (like two browsers)
18
- const userAContext = await browser.newContext();
19
- const userBContext = await browser.newContext();
20
-
21
- const userAPage = await userAContext.newPage();
22
- const userBPage = await userBContext.newPage();
23
-
24
- // Both users go to the same document
25
- await userAPage.goto("/doc/shared-123");
26
- await userBPage.goto("/doc/shared-123");
27
-
28
- // User A types
29
- await userAPage.getByLabel("Content").fill("Hello from User A");
30
-
31
- // User B should see the change
32
- await expect(userBPage.getByText("Hello from User A")).toBeVisible();
33
-
34
- // Cleanup
35
- await userAContext.close();
36
- await userBContext.close();
37
- });
38
- ```
39
-
40
- ### Multiple Users with Auth States
41
-
42
- ```typescript
43
- test("admin and user interaction", async ({ browser }) => {
44
- // Load different auth states
45
- const adminContext = await browser.newContext({
46
- storageState: ".auth/admin.json",
47
- });
48
- const userContext = await browser.newContext({
49
- storageState: ".auth/user.json",
50
- });
51
-
52
- const adminPage = await adminContext.newPage();
53
- const userPage = await userContext.newPage();
54
-
55
- // User submits request
56
- await userPage.goto("/support");
57
- await userPage.getByLabel("Message").fill("Need help!");
58
- await userPage.getByRole("button", { name: "Submit" }).click();
59
-
60
- // Admin sees and responds
61
- await adminPage.goto("/admin/tickets");
62
- await expect(adminPage.getByText("Need help!")).toBeVisible();
63
- await adminPage.getByRole("button", { name: "Reply" }).click();
64
- await adminPage.getByLabel("Response").fill("How can I help?");
65
- await adminPage.getByRole("button", { name: "Send" }).click();
66
-
67
- // User sees response
68
- await expect(userPage.getByText("How can I help?")).toBeVisible();
69
-
70
- await adminContext.close();
71
- await userContext.close();
72
- });
73
- ```
74
-
75
- ### Multi-User Fixture
76
-
77
- ```typescript
78
- // fixtures/multi-user.fixture.ts
79
- import { test as base, Browser, BrowserContext, Page } from "@playwright/test";
80
-
81
- type UserSession = {
82
- context: BrowserContext;
83
- page: Page;
84
- };
85
-
86
- type MultiUserFixtures = {
87
- createUser: (authState?: string) => Promise<UserSession>;
88
- };
89
-
90
- export const test = base.extend<MultiUserFixtures>({
91
- createUser: async ({ browser }, use) => {
92
- const sessions: UserSession[] = [];
93
-
94
- await use(async (authState) => {
95
- const context = await browser.newContext({
96
- storageState: authState,
97
- });
98
- const page = await context.newPage();
99
- sessions.push({ context, page });
100
- return { context, page };
101
- });
102
-
103
- // Cleanup all sessions
104
- for (const session of sessions) {
105
- await session.context.close();
106
- }
107
- },
108
- });
109
-
110
- // Usage
111
- test("3 users collaborate", async ({ createUser }) => {
112
- const alice = await createUser(".auth/alice.json");
113
- const bob = await createUser(".auth/bob.json");
114
- const charlie = await createUser(".auth/charlie.json");
115
-
116
- // All navigate to same room
117
- await alice.page.goto("/room/123");
118
- await bob.page.goto("/room/123");
119
- await charlie.page.goto("/room/123");
120
-
121
- // Test interactions...
122
- });
123
- ```
124
-
125
- ## Real-Time Collaboration
126
-
127
- ### Collaborative Document
128
-
129
- ```typescript
130
- test("real-time collaborative editing", async ({ browser }) => {
131
- const user1 = await browser.newContext();
132
- const user2 = await browser.newContext();
133
-
134
- const page1 = await user1.newPage();
135
- const page2 = await user2.newPage();
136
-
137
- await page1.goto("/docs/shared");
138
- await page2.goto("/docs/shared");
139
-
140
- // User 1 types at the beginning
141
- const editor1 = page1.getByRole("textbox");
142
- await editor1.click();
143
- await editor1.press("Home");
144
- await editor1.type("User 1: ");
145
-
146
- // User 2 types at the end
147
- const editor2 = page2.getByRole("textbox");
148
- await editor2.click();
149
- await editor2.press("End");
150
- await editor2.type(" - User 2");
151
-
152
- // Both should see combined result
153
- await expect(page1.getByRole("textbox")).toContainText("User 1:");
154
- await expect(page1.getByRole("textbox")).toContainText("- User 2");
155
- await expect(page2.getByRole("textbox")).toContainText("User 1:");
156
- await expect(page2.getByRole("textbox")).toContainText("- User 2");
157
-
158
- await user1.close();
159
- await user2.close();
160
- });
161
- ```
162
-
163
- ### Cursor Presence
164
-
165
- ```typescript
166
- test("shows other user cursors", async ({ browser }) => {
167
- const ctx1 = await browser.newContext();
168
- const ctx2 = await browser.newContext();
169
-
170
- const page1 = await ctx1.newPage();
171
- const page2 = await ctx2.newPage();
172
-
173
- // Mock to identify users
174
- await page1.route("**/api/me", (route) =>
175
- route.fulfill({ json: { id: "user-1", name: "Alice" } }),
176
- );
177
- await page2.route("**/api/me", (route) =>
178
- route.fulfill({ json: { id: "user-2", name: "Bob" } }),
179
- );
180
-
181
- await page1.goto("/whiteboard/123");
182
- await page2.goto("/whiteboard/123");
183
-
184
- // Move cursor on page1
185
- await page1.mouse.move(200, 200);
186
-
187
- // Page2 should see Alice's cursor
188
- await expect(page2.getByTestId("cursor-user-1")).toBeVisible();
189
- await expect(page2.getByText("Alice")).toBeVisible();
190
-
191
- await ctx1.close();
192
- await ctx2.close();
193
- });
194
- ```
195
-
196
- ## Role-Based Testing
197
-
198
- ### Test RBAC
199
-
200
- ```typescript
201
- const roles = [
202
- { role: "admin", canDelete: true, canEdit: true, canView: true },
203
- { role: "editor", canDelete: false, canEdit: true, canView: true },
204
- { role: "viewer", canDelete: false, canEdit: false, canView: true },
205
- ];
206
-
207
- for (const { role, canDelete, canEdit, canView } of roles) {
208
- test(`${role} permissions`, async ({ browser }) => {
209
- const context = await browser.newContext({
210
- storageState: `.auth/${role}.json`,
211
- });
212
- const page = await context.newPage();
213
-
214
- await page.goto("/document/123");
215
-
216
- // Check view permission
217
- if (canView) {
218
- await expect(page.getByTestId("content")).toBeVisible();
219
- } else {
220
- await expect(page.getByText("Access denied")).toBeVisible();
221
- }
222
-
223
- // Check edit permission
224
- const editButton = page.getByRole("button", { name: "Edit" });
225
- if (canEdit) {
226
- await expect(editButton).toBeEnabled();
227
- } else {
228
- await expect(editButton).toBeDisabled();
229
- }
230
-
231
- // Check delete permission
232
- const deleteButton = page.getByRole("button", { name: "Delete" });
233
- if (canDelete) {
234
- await expect(deleteButton).toBeVisible();
235
- } else {
236
- await expect(deleteButton).toBeHidden();
237
- }
238
-
239
- await context.close();
240
- });
241
- }
242
- ```
243
-
244
- ### Permission Escalation Test
245
-
246
- ```typescript
247
- test("cannot access admin routes as user", async ({ browser }) => {
248
- const userContext = await browser.newContext({
249
- storageState: ".auth/user.json",
250
- });
251
- const page = await userContext.newPage();
252
-
253
- // Try to access admin page directly
254
- await page.goto("/admin/users");
255
-
256
- // Should redirect or show error
257
- await expect(page).not.toHaveURL("/admin/users");
258
- await expect(page.getByText("Access denied")).toBeVisible();
259
-
260
- await userContext.close();
261
- });
262
- ```
263
-
264
- ## Concurrent Actions
265
-
266
- ### Race Condition Testing
267
-
268
- ```typescript
269
- test("handles concurrent edits", async ({ browser }) => {
270
- const ctx1 = await browser.newContext();
271
- const ctx2 = await browser.newContext();
272
-
273
- const page1 = await ctx1.newPage();
274
- const page2 = await ctx2.newPage();
275
-
276
- await page1.goto("/item/123");
277
- await page2.goto("/item/123");
278
-
279
- // Both click edit at the same time
280
- await Promise.all([
281
- page1.getByRole("button", { name: "Edit" }).click(),
282
- page2.getByRole("button", { name: "Edit" }).click(),
283
- ]);
284
-
285
- // Both try to save different values
286
- await page1.getByLabel("Name").fill("Value from User 1");
287
- await page2.getByLabel("Name").fill("Value from User 2");
288
-
289
- await Promise.all([
290
- page1.getByRole("button", { name: "Save" }).click(),
291
- page2.getByRole("button", { name: "Save" }).click(),
292
- ]);
293
-
294
- // One should succeed, one should get conflict error
295
- const page1HasConflict = await page1.getByText("Conflict").isVisible();
296
- const page2HasConflict = await page2.getByText("Conflict").isVisible();
297
-
298
- // Exactly one should have conflict
299
- expect(page1HasConflict || page2HasConflict).toBe(true);
300
- expect(page1HasConflict && page2HasConflict).toBe(false);
301
-
302
- await ctx1.close();
303
- await ctx2.close();
304
- });
305
- ```
306
-
307
- ### Optimistic Locking Test
308
-
309
- ```typescript
310
- test("optimistic locking prevents overwrites", async ({ browser }) => {
311
- const ctx1 = await browser.newContext();
312
- const ctx2 = await browser.newContext();
313
-
314
- const page1 = await ctx1.newPage();
315
- const page2 = await ctx2.newPage();
316
-
317
- // Both load the same version
318
- await page1.goto("/record/123");
319
- await page2.goto("/record/123");
320
-
321
- // User 1 edits and saves first
322
- await page1.getByRole("button", { name: "Edit" }).click();
323
- await page1.getByLabel("Value").fill("Updated by User 1");
324
- await page1.getByRole("button", { name: "Save" }).click();
325
- await expect(page1.getByText("Saved")).toBeVisible();
326
-
327
- // User 2 tries to save with stale version
328
- await page2.getByRole("button", { name: "Edit" }).click();
329
- await page2.getByLabel("Value").fill("Updated by User 2");
330
- await page2.getByRole("button", { name: "Save" }).click();
331
-
332
- // Should fail with version conflict
333
- await expect(page2.getByText("Someone else modified this")).toBeVisible();
334
- await expect(page2.getByRole("button", { name: "Reload" })).toBeVisible();
335
-
336
- await ctx1.close();
337
- await ctx2.close();
338
- });
339
- ```
340
-
341
- ## Chat & Messaging
342
-
343
- ### Real-Time Chat
344
-
345
- ```typescript
346
- test("chat messages sync between users", async ({ browser }) => {
347
- const aliceCtx = await browser.newContext();
348
- const bobCtx = await browser.newContext();
349
-
350
- const alicePage = await aliceCtx.newPage();
351
- const bobPage = await bobCtx.newPage();
352
-
353
- // Setup user identities
354
- await alicePage.route("**/api/me", (r) =>
355
- r.fulfill({ json: { name: "Alice" } }),
356
- );
357
- await bobPage.route("**/api/me", (r) => r.fulfill({ json: { name: "Bob" } }));
358
-
359
- await alicePage.goto("/chat/room-1");
360
- await bobPage.goto("/chat/room-1");
361
-
362
- // Alice sends message
363
- await alicePage.getByLabel("Message").fill("Hi Bob!");
364
- await alicePage.getByRole("button", { name: "Send" }).click();
365
-
366
- // Bob sees it
367
- await expect(bobPage.getByText("Alice: Hi Bob!")).toBeVisible();
368
-
369
- // Bob replies
370
- await bobPage.getByLabel("Message").fill("Hey Alice!");
371
- await bobPage.getByRole("button", { name: "Send" }).click();
372
-
373
- // Alice sees it
374
- await expect(alicePage.getByText("Bob: Hey Alice!")).toBeVisible();
375
-
376
- await aliceCtx.close();
377
- await bobCtx.close();
378
- });
379
- ```
380
-
381
- ## Anti-Patterns to Avoid
382
-
383
- | Anti-Pattern | Problem | Solution |
384
- | ----------------------------- | ----------------------------- | ---------------------------- |
385
- | Sharing context between users | State leaks, not isolated | Create separate contexts |
386
- | Not closing contexts | Memory leak, browser overload | Always close in cleanup |
387
- | Hardcoded timing for sync | Flaky tests | Use `expect().toBeVisible()` |
388
- | Testing only single user | Misses collaboration bugs | Test multi-user scenarios |
389
-
390
- ## Related References
391
-
392
- - **Authentication**: See [fixtures-hooks.md](../core/fixtures-hooks.md) for auth setup
393
- - **WebSockets**: See [websockets.md](../browser-apis/websockets.md) for real-time mocking