@drmxrcy/tcg-lorcana 0.0.0-202602060544

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 (100) hide show
  1. package/README.md +160 -0
  2. package/package.json +45 -0
  3. package/src/__tests__/integration/move-enumeration.test.ts +256 -0
  4. package/src/__tests__/rules/section-01-concepts.test.ts +426 -0
  5. package/src/__tests__/rules/section-03-gameplay.test.ts +298 -0
  6. package/src/__tests__/rules/section-04-turn-structure.test.ts +708 -0
  7. package/src/__tests__/rules/section-05-cards.test.ts +158 -0
  8. package/src/__tests__/rules/section-06-card-types.test.ts +342 -0
  9. package/src/__tests__/rules/section-07-abilities.test.ts +333 -0
  10. package/src/__tests__/rules/section-08-zones.test.ts +231 -0
  11. package/src/__tests__/rules/section-09-damage.test.ts +148 -0
  12. package/src/__tests__/rules/section-10-keywords.test.ts +469 -0
  13. package/src/__tests__/spec-01-foundation-types.test.ts +534 -0
  14. package/src/__tests__/spec-02-zones-card-states.test.ts +295 -0
  15. package/src/card-utils.ts +302 -0
  16. package/src/cards/README.md +296 -0
  17. package/src/cards/abilities/index.ts +175 -0
  18. package/src/cards/index.ts +10 -0
  19. package/src/deck-validation.ts +175 -0
  20. package/src/engine/lorcana-engine.ts +625 -0
  21. package/src/game-definition/__tests__/core-zone-integration.test.ts +553 -0
  22. package/src/game-definition/__tests__/zone-operations.test.ts +362 -0
  23. package/src/game-definition/__tests__/zones.test.ts +176 -0
  24. package/src/game-definition/definition.ts +45 -0
  25. package/src/game-definition/flow/turn-flow.ts +216 -0
  26. package/src/game-definition/index.ts +31 -0
  27. package/src/game-definition/moves/abilities/activate-ability.ts +51 -0
  28. package/src/game-definition/moves/core/__tests__/move-parameter-enumeration.test.ts +316 -0
  29. package/src/game-definition/moves/core/challenge.test.ts +545 -0
  30. package/src/game-definition/moves/core/challenge.ts +81 -0
  31. package/src/game-definition/moves/core/play-card.ts +83 -0
  32. package/src/game-definition/moves/core/quest.test.ts +448 -0
  33. package/src/game-definition/moves/core/quest.ts +49 -0
  34. package/src/game-definition/moves/debug/manual-exert.ts +36 -0
  35. package/src/game-definition/moves/effects/resolve-bag.ts +35 -0
  36. package/src/game-definition/moves/effects/resolve-effect.ts +34 -0
  37. package/src/game-definition/moves/index.ts +85 -0
  38. package/src/game-definition/moves/locations/move-character-to-location.ts +42 -0
  39. package/src/game-definition/moves/resources/put-card-into-inkwell.test.ts +462 -0
  40. package/src/game-definition/moves/resources/put-card-into-inkwell.ts +51 -0
  41. package/src/game-definition/moves/setup/alter-hand.test.ts +395 -0
  42. package/src/game-definition/moves/setup/alter-hand.ts +210 -0
  43. package/src/game-definition/moves/setup/choose-first-player.test.ts +450 -0
  44. package/src/game-definition/moves/setup/choose-first-player.ts +105 -0
  45. package/src/game-definition/moves/setup/draw-cards.ts +37 -0
  46. package/src/game-definition/moves/songs/sing-together.ts +47 -0
  47. package/src/game-definition/moves/songs/sing.ts +56 -0
  48. package/src/game-definition/moves/standard/concede.test.ts +189 -0
  49. package/src/game-definition/moves/standard/concede.ts +72 -0
  50. package/src/game-definition/moves/standard/pass-turn.ts +49 -0
  51. package/src/game-definition/setup/game-setup.ts +19 -0
  52. package/src/game-definition/trackers/tracker-config.ts +23 -0
  53. package/src/game-definition/win-conditions/lore-victory.ts +26 -0
  54. package/src/game-definition/zone-operations.ts +405 -0
  55. package/src/game-definition/zones/zone-configs.ts +59 -0
  56. package/src/game-definition/zones.ts +283 -0
  57. package/src/index.ts +189 -0
  58. package/src/operations/index.ts +7 -0
  59. package/src/operations/lorcana-operations.ts +288 -0
  60. package/src/queries/README.md +56 -0
  61. package/src/resolvers/__tests__/condition-resolver.test.ts +301 -0
  62. package/src/resolvers/condition-registry.ts +70 -0
  63. package/src/resolvers/condition-resolver.ts +85 -0
  64. package/src/resolvers/conditions/basic.ts +81 -0
  65. package/src/resolvers/conditions/card-state.ts +12 -0
  66. package/src/resolvers/conditions/comparison.ts +102 -0
  67. package/src/resolvers/conditions/existence.ts +219 -0
  68. package/src/resolvers/conditions/history.ts +68 -0
  69. package/src/resolvers/conditions/index.ts +15 -0
  70. package/src/resolvers/conditions/logical.ts +55 -0
  71. package/src/resolvers/conditions/resolution.ts +41 -0
  72. package/src/resolvers/conditions/revealed.ts +42 -0
  73. package/src/resolvers/conditions/zone.ts +84 -0
  74. package/src/setup.test.ts +18 -0
  75. package/src/targeting/__tests__/filter-resolver.test.ts +294 -0
  76. package/src/targeting/__tests__/real-cards-targeting.test.ts +303 -0
  77. package/src/targeting/__tests__/targeting-dsl.test.ts +386 -0
  78. package/src/targeting/enum-expansion.ts +387 -0
  79. package/src/targeting/filter-registry.ts +322 -0
  80. package/src/targeting/filter-resolver.ts +145 -0
  81. package/src/targeting/index.ts +91 -0
  82. package/src/targeting/lorcana-target-dsl.ts +495 -0
  83. package/src/targeting/targeting-ui.ts +407 -0
  84. package/src/testing/index.ts +14 -0
  85. package/src/testing/lorcana-test-engine.ts +813 -0
  86. package/src/types/README.md +303 -0
  87. package/src/types/__tests__/lorcana-state.test.ts +168 -0
  88. package/src/types/__tests__/move-enumeration.test.ts +179 -0
  89. package/src/types/branded-types.ts +106 -0
  90. package/src/types/game-state.ts +184 -0
  91. package/src/types/index.ts +87 -0
  92. package/src/types/keywords.ts +187 -0
  93. package/src/types/lorcana-state.ts +260 -0
  94. package/src/types/move-enumeration.ts +126 -0
  95. package/src/types/move-params.ts +216 -0
  96. package/src/validators/index.ts +7 -0
  97. package/src/validators/move-validators.ts +374 -0
  98. package/src/zones/card-state.ts +234 -0
  99. package/src/zones/index.ts +42 -0
  100. package/src/zones/zone-config.ts +150 -0
@@ -0,0 +1,553 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import {
3
+ addCard,
4
+ addCardToBottom,
5
+ addCardToTop,
6
+ clearZone,
7
+ createCardId,
8
+ createPlayerId,
9
+ createPlayerZones,
10
+ createZone,
11
+ createZoneId,
12
+ getCardsInZone,
13
+ getTopCard,
14
+ getZoneSize,
15
+ isCardInZone,
16
+ moveCard,
17
+ removeCard,
18
+ } from "@drmxrcy/tcg-core";
19
+
20
+ /**
21
+ * Task 7.2: Tests verifying lorcana zone operations work with core utilities
22
+ *
23
+ * These tests verify that core zone operations from @drmxrcy/tcg-core can handle
24
+ * Lorcana's zone management needs, validating the migration path.
25
+ *
26
+ * Tests cover:
27
+ * - Zone creation for multiple players
28
+ * - Card operations (add, remove, move)
29
+ * - Zone queries (size, cards, top card)
30
+ * - Ordered zone operations (top/bottom)
31
+ * - Real-world Lorcana scenarios (draw, play, banish, ink)
32
+ */
33
+
34
+ // Test helpers
35
+ function createTestPlayers(...names: string[]) {
36
+ return names.map((name) => createPlayerId(name));
37
+ }
38
+
39
+ function _createTestCards(...names: string[]) {
40
+ return names.map((name) => createCardId(name));
41
+ }
42
+
43
+ describe("Core Zone Integration for Lorcana", () => {
44
+ describe("Zone Creation", () => {
45
+ it("should create zones for multiple players using core utilities", () => {
46
+ const [player1, player2] = createTestPlayers("player1", "player2");
47
+
48
+ // Use core's createPlayerZones helper
49
+ const handZones = createPlayerZones([player1, player2], () =>
50
+ createZone({
51
+ id: createZoneId("hand"),
52
+ name: "Hand",
53
+ visibility: "private",
54
+ ordered: false,
55
+ }),
56
+ );
57
+
58
+ expect(handZones[player1]).toBeDefined();
59
+ expect(handZones[player2]).toBeDefined();
60
+ expect(handZones[player1].cards).toEqual([]);
61
+ expect(handZones[player2].cards).toEqual([]);
62
+ });
63
+
64
+ it("should create all 5 Lorcana zones with correct configurations", () => {
65
+ const [player1] = createTestPlayers("player1");
66
+
67
+ const deckZone = createZone({
68
+ id: createZoneId("deck"),
69
+ name: "Deck",
70
+ visibility: "secret",
71
+ ordered: true,
72
+ owner: player1,
73
+ faceDown: true,
74
+ });
75
+
76
+ const handZone = createZone({
77
+ id: createZoneId("hand"),
78
+ name: "Hand",
79
+ visibility: "private",
80
+ ordered: false,
81
+ owner: player1,
82
+ });
83
+
84
+ const playZone = createZone({
85
+ id: createZoneId("play"),
86
+ name: "Play",
87
+ visibility: "public",
88
+ ordered: false,
89
+ owner: player1,
90
+ });
91
+
92
+ const discardZone = createZone({
93
+ id: createZoneId("discard"),
94
+ name: "Discard",
95
+ visibility: "public",
96
+ ordered: true,
97
+ owner: player1,
98
+ });
99
+
100
+ const inkwellZone = createZone({
101
+ id: createZoneId("inkwell"),
102
+ name: "Inkwell",
103
+ visibility: "secret",
104
+ ordered: false,
105
+ owner: player1,
106
+ faceDown: true,
107
+ });
108
+
109
+ expect(deckZone.config.visibility).toBe("secret");
110
+ expect(deckZone.config.ordered).toBe(true);
111
+ expect(handZone.config.visibility).toBe("private");
112
+ expect(playZone.config.visibility).toBe("public");
113
+ expect(discardZone.config.ordered).toBe(true);
114
+ expect(inkwellZone.config.faceDown).toBe(true);
115
+ });
116
+ });
117
+
118
+ describe("Basic Zone Operations", () => {
119
+ it("should add card to zone using core addCard", () => {
120
+ const player1 = createPlayerId("player1");
121
+ const card1 = createCardId("card-1");
122
+
123
+ const handZone = createZone({
124
+ id: createZoneId("hand"),
125
+ name: "Hand",
126
+ visibility: "private",
127
+ ordered: false,
128
+ owner: player1,
129
+ });
130
+
131
+ const updatedHand = addCard(handZone, card1);
132
+
133
+ expect(updatedHand.cards).toEqual([card1]);
134
+ expect(handZone.cards).toEqual([]); // Original unchanged (immutable)
135
+ });
136
+
137
+ it("should remove card from zone using core removeCard", () => {
138
+ const player1 = createPlayerId("player1");
139
+ const card1 = createCardId("card-1");
140
+ const card2 = createCardId("card-2");
141
+
142
+ let handZone = createZone({
143
+ id: createZoneId("hand"),
144
+ name: "Hand",
145
+ visibility: "private",
146
+ ordered: false,
147
+ owner: player1,
148
+ });
149
+
150
+ handZone = addCard(handZone, card1);
151
+ handZone = addCard(handZone, card2);
152
+
153
+ const updatedHand = removeCard(handZone, card1);
154
+
155
+ expect(updatedHand.cards).toEqual([card2]);
156
+ });
157
+
158
+ it("should move card between zones using core moveCard", () => {
159
+ const player1 = createPlayerId("player1");
160
+ const card1 = createCardId("card-1");
161
+
162
+ let handZone = createZone({
163
+ id: createZoneId("hand"),
164
+ name: "Hand",
165
+ visibility: "private",
166
+ ordered: false,
167
+ owner: player1,
168
+ });
169
+
170
+ const playZone = createZone({
171
+ id: createZoneId("play"),
172
+ name: "Play",
173
+ visibility: "public",
174
+ ordered: false,
175
+ owner: player1,
176
+ });
177
+
178
+ handZone = addCard(handZone, card1);
179
+
180
+ const { fromZone: updatedHand, toZone: updatedPlay } = moveCard(
181
+ handZone,
182
+ playZone,
183
+ card1,
184
+ );
185
+
186
+ expect(updatedHand.cards).toEqual([]);
187
+ expect(updatedPlay.cards).toEqual([card1]);
188
+ });
189
+ });
190
+
191
+ describe("Zone Queries", () => {
192
+ it("should check if card is in zone using core isCardInZone", () => {
193
+ const player1 = createPlayerId("player1");
194
+ const card1 = createCardId("card-1");
195
+ const card2 = createCardId("card-2");
196
+
197
+ let handZone = createZone({
198
+ id: createZoneId("hand"),
199
+ name: "Hand",
200
+ visibility: "private",
201
+ ordered: false,
202
+ owner: player1,
203
+ });
204
+
205
+ handZone = addCard(handZone, card1);
206
+
207
+ expect(isCardInZone(handZone, card1)).toBe(true);
208
+ expect(isCardInZone(handZone, card2)).toBe(false);
209
+ });
210
+
211
+ it("should get all cards in zone using core getCardsInZone", () => {
212
+ const player1 = createPlayerId("player1");
213
+ const card1 = createCardId("card-1");
214
+ const card2 = createCardId("card-2");
215
+ const card3 = createCardId("card-3");
216
+
217
+ let handZone = createZone({
218
+ id: createZoneId("hand"),
219
+ name: "Hand",
220
+ visibility: "private",
221
+ ordered: false,
222
+ owner: player1,
223
+ });
224
+
225
+ handZone = addCard(handZone, card1);
226
+ handZone = addCard(handZone, card2);
227
+ handZone = addCard(handZone, card3);
228
+
229
+ const cards = getCardsInZone(handZone);
230
+
231
+ expect(cards).toEqual([card1, card2, card3]);
232
+ });
233
+
234
+ it("should get zone size using core getZoneSize", () => {
235
+ const player1 = createPlayerId("player1");
236
+ const card1 = createCardId("card-1");
237
+ const card2 = createCardId("card-2");
238
+
239
+ let deckZone = createZone({
240
+ id: createZoneId("deck"),
241
+ name: "Deck",
242
+ visibility: "secret",
243
+ ordered: true,
244
+ owner: player1,
245
+ });
246
+
247
+ deckZone = addCard(deckZone, card1);
248
+ deckZone = addCard(deckZone, card2);
249
+
250
+ expect(getZoneSize(deckZone)).toBe(2);
251
+ });
252
+
253
+ it("should get top card using core getTopCard", () => {
254
+ const player1 = createPlayerId("player1");
255
+ const topCard = createCardId("top-card");
256
+ const card2 = createCardId("card-2");
257
+
258
+ let deckZone = createZone({
259
+ id: createZoneId("deck"),
260
+ name: "Deck",
261
+ visibility: "secret",
262
+ ordered: true,
263
+ owner: player1,
264
+ });
265
+
266
+ deckZone = addCard(deckZone, topCard);
267
+ deckZone = addCard(deckZone, card2);
268
+
269
+ expect(getTopCard(deckZone)).toBe(topCard);
270
+ });
271
+ });
272
+
273
+ describe("Ordered Zone Operations", () => {
274
+ it("should add card to top of zone using core addCardToTop", () => {
275
+ const player1 = createPlayerId("player1");
276
+ const card1 = createCardId("card-1");
277
+ const card2 = createCardId("card-2");
278
+
279
+ let deckZone = createZone({
280
+ id: createZoneId("deck"),
281
+ name: "Deck",
282
+ visibility: "secret",
283
+ ordered: true,
284
+ owner: player1,
285
+ });
286
+
287
+ deckZone = addCard(deckZone, card1);
288
+ deckZone = addCardToTop(deckZone, card2);
289
+
290
+ expect(deckZone.cards[0]).toBe(card2);
291
+ expect(deckZone.cards[1]).toBe(card1);
292
+ });
293
+
294
+ it("should add card to bottom of zone using core addCardToBottom", () => {
295
+ const player1 = createPlayerId("player1");
296
+ const card1 = createCardId("card-1");
297
+ const card2 = createCardId("card-2");
298
+
299
+ let deckZone = createZone({
300
+ id: createZoneId("deck"),
301
+ name: "Deck",
302
+ visibility: "secret",
303
+ ordered: true,
304
+ owner: player1,
305
+ });
306
+
307
+ deckZone = addCard(deckZone, card1);
308
+ deckZone = addCardToBottom(deckZone, card2);
309
+
310
+ expect(deckZone.cards[0]).toBe(card1);
311
+ expect(deckZone.cards[1]).toBe(card2);
312
+ });
313
+
314
+ it("should clear zone using core clearZone", () => {
315
+ const player1 = createPlayerId("player1");
316
+ const card1 = createCardId("card-1");
317
+ const card2 = createCardId("card-2");
318
+
319
+ let handZone = createZone({
320
+ id: createZoneId("hand"),
321
+ name: "Hand",
322
+ visibility: "private",
323
+ ordered: false,
324
+ owner: player1,
325
+ });
326
+
327
+ handZone = addCard(handZone, card1);
328
+ handZone = addCard(handZone, card2);
329
+
330
+ const clearedHand = clearZone(handZone);
331
+
332
+ expect(clearedHand.cards).toEqual([]);
333
+ });
334
+ });
335
+
336
+ describe("Lorcana Scenario Tests", () => {
337
+ it("should handle draw card scenario (deck -> hand)", () => {
338
+ const player1 = createPlayerId("player1");
339
+ const topCard = createCardId("top-card");
340
+ const card2 = createCardId("card-2");
341
+ const card3 = createCardId("card-3");
342
+
343
+ let deckZone = createZone({
344
+ id: createZoneId("deck"),
345
+ name: "Deck",
346
+ visibility: "secret",
347
+ ordered: true,
348
+ owner: player1,
349
+ });
350
+
351
+ const handZone = createZone({
352
+ id: createZoneId("hand"),
353
+ name: "Hand",
354
+ visibility: "private",
355
+ ordered: false,
356
+ owner: player1,
357
+ });
358
+
359
+ deckZone = addCard(deckZone, topCard);
360
+ deckZone = addCard(deckZone, card2);
361
+ deckZone = addCard(deckZone, card3);
362
+
363
+ // Draw top card
364
+ const { fromZone: updatedDeck, toZone: updatedHand } = moveCard(
365
+ deckZone,
366
+ handZone,
367
+ topCard,
368
+ );
369
+
370
+ expect(getZoneSize(updatedDeck)).toBe(2);
371
+ expect(updatedHand.cards).toContain(topCard);
372
+ });
373
+
374
+ it("should handle play card scenario (hand -> play)", () => {
375
+ const player1 = createPlayerId("player1");
376
+ const character = createCardId("character-1");
377
+
378
+ let handZone = createZone({
379
+ id: createZoneId("hand"),
380
+ name: "Hand",
381
+ visibility: "private",
382
+ ordered: false,
383
+ owner: player1,
384
+ });
385
+
386
+ const playZone = createZone({
387
+ id: createZoneId("play"),
388
+ name: "Play",
389
+ visibility: "public",
390
+ ordered: false,
391
+ owner: player1,
392
+ });
393
+
394
+ handZone = addCard(handZone, character);
395
+
396
+ const { fromZone: updatedHand, toZone: updatedPlay } = moveCard(
397
+ handZone,
398
+ playZone,
399
+ character,
400
+ );
401
+
402
+ expect(updatedHand.cards).toEqual([]);
403
+ expect(updatedPlay.cards).toContain(character);
404
+ });
405
+
406
+ it("should handle banish scenario (play -> discard)", () => {
407
+ const player1 = createPlayerId("player1");
408
+ const character = createCardId("character-1");
409
+
410
+ let playZone = createZone({
411
+ id: createZoneId("play"),
412
+ name: "Play",
413
+ visibility: "public",
414
+ ordered: false,
415
+ owner: player1,
416
+ });
417
+
418
+ const discardZone = createZone({
419
+ id: createZoneId("discard"),
420
+ name: "Discard",
421
+ visibility: "public",
422
+ ordered: true,
423
+ owner: player1,
424
+ });
425
+
426
+ playZone = addCard(playZone, character);
427
+
428
+ const { fromZone: updatedPlay, toZone: updatedDiscard } = moveCard(
429
+ playZone,
430
+ discardZone,
431
+ character,
432
+ );
433
+
434
+ expect(updatedPlay.cards).toEqual([]);
435
+ expect(updatedDiscard.cards).toContain(character);
436
+ });
437
+
438
+ it("should handle ink card scenario (hand -> inkwell)", () => {
439
+ const player1 = createPlayerId("player1");
440
+ const inkableCard = createCardId("inkable-1");
441
+
442
+ let handZone = createZone({
443
+ id: createZoneId("hand"),
444
+ name: "Hand",
445
+ visibility: "private",
446
+ ordered: false,
447
+ owner: player1,
448
+ });
449
+
450
+ const inkwellZone = createZone({
451
+ id: createZoneId("inkwell"),
452
+ name: "Inkwell",
453
+ visibility: "secret",
454
+ ordered: false,
455
+ owner: player1,
456
+ faceDown: true,
457
+ });
458
+
459
+ handZone = addCard(handZone, inkableCard);
460
+
461
+ const { fromZone: updatedHand, toZone: updatedInkwell } = moveCard(
462
+ handZone,
463
+ inkwellZone,
464
+ inkableCard,
465
+ );
466
+
467
+ expect(updatedHand.cards).toEqual([]);
468
+ expect(updatedInkwell.cards).toContain(inkableCard);
469
+ });
470
+
471
+ it("should handle mulligan scenario (put cards on bottom of deck)", () => {
472
+ const player1 = createPlayerId("player1");
473
+ const mulliganCard1 = createCardId("mulligan-1");
474
+ const mulliganCard2 = createCardId("mulligan-2");
475
+ const deckCard1 = createCardId("deck-1");
476
+ const deckCard2 = createCardId("deck-2");
477
+
478
+ let deckZone = createZone({
479
+ id: createZoneId("deck"),
480
+ name: "Deck",
481
+ visibility: "secret",
482
+ ordered: true,
483
+ owner: player1,
484
+ });
485
+
486
+ // Deck has some cards
487
+ deckZone = addCard(deckZone, deckCard1);
488
+ deckZone = addCard(deckZone, deckCard2);
489
+
490
+ // Put mulligan cards on bottom
491
+ deckZone = addCardToBottom(deckZone, mulliganCard1);
492
+ deckZone = addCardToBottom(deckZone, mulliganCard2);
493
+
494
+ // Check order: original deck cards on top, mulligan cards on bottom
495
+ expect(deckZone.cards[0]).toBe(deckCard1);
496
+ expect(deckZone.cards[1]).toBe(deckCard2);
497
+ expect(deckZone.cards[2]).toBe(mulliganCard1);
498
+ expect(deckZone.cards[3]).toBe(mulliganCard2);
499
+ });
500
+ });
501
+
502
+ describe("Immutability Tests", () => {
503
+ it("should not mutate original zone when adding cards", () => {
504
+ const player1 = createPlayerId("player1");
505
+ const card1 = createCardId("card-1");
506
+
507
+ const originalZone = createZone({
508
+ id: createZoneId("hand"),
509
+ name: "Hand",
510
+ visibility: "private",
511
+ ordered: false,
512
+ owner: player1,
513
+ });
514
+
515
+ const updatedZone = addCard(originalZone, card1);
516
+
517
+ expect(originalZone.cards).toEqual([]);
518
+ expect(updatedZone.cards).toEqual([card1]);
519
+ });
520
+
521
+ it("should not mutate original zones when moving cards", () => {
522
+ const player1 = createPlayerId("player1");
523
+ const card1 = createCardId("card-1");
524
+
525
+ let handZone = createZone({
526
+ id: createZoneId("hand"),
527
+ name: "Hand",
528
+ visibility: "private",
529
+ ordered: false,
530
+ owner: player1,
531
+ });
532
+
533
+ const playZone = createZone({
534
+ id: createZoneId("play"),
535
+ name: "Play",
536
+ visibility: "public",
537
+ ordered: false,
538
+ owner: player1,
539
+ });
540
+
541
+ handZone = addCard(handZone, card1);
542
+
543
+ const originalHandCards = [...handZone.cards];
544
+ const originalPlayCards = [...playZone.cards];
545
+
546
+ moveCard(handZone, playZone, card1);
547
+
548
+ // Original zones unchanged
549
+ expect(handZone.cards).toEqual(originalHandCards);
550
+ expect(playZone.cards).toEqual(originalPlayCards);
551
+ });
552
+ });
553
+ });