How to use stateChanged method in Testcafe

Best JavaScript code snippet using testcafe

putDownCardTests.js

Source:putDownCardTests.js Github

copy

Full Screen

1const {2 bocha: { assert, refute, sinon },3 createCard,4 Player,5 createPlayer,6 createMatch,7 FakeConnection2,8 catchError,9 createState,10 FakeDeck,11} = require("./shared.js");12const PutDownCardEvent = require("../../../../shared/PutDownCardEvent.js");13const MissilesLaunched = require("../../../../shared/card/MissilesLaunched.js");14const Sabotage = require("../../../../shared/card/Sabotage.js");15const StateAsserter = require("../../testUtils/StateAsserter.js");16const GrandOpportunityCommonId = "20";17const ExcellentWorkCommonId = "14";18const SupernovaCommonId = "15";19const DiscoveryCommonId = "42";20const FatalErrorCommonId = "38";21const ExpansionCommonId = "40";22module.exports = {23 "when does NOT have card should throw error": function () {24 this.match = createMatch({ players: [Player("P1A")] });25 this.match.restoreFromState(26 createState({27 turn: 2,28 currentPlayer: "P1A",29 playerOrder: ["P1A", "P2A"],30 playerStateById: {31 P1A: {32 phase: "action",33 cardsOnHand: [],34 },35 },36 })37 );38 const putDownCardOptions = { location: "zone", cardId: "C1A" };39 const error = catchError(() =>40 this.match.putDownCard("P1A", putDownCardOptions)41 );42 assert.equals(error.message, "Cannot find card");43 },44 "when does NOT have enough action points to place card in zone": function () {45 this.match = createMatch({ players: [Player("P1A")] });46 this.match.restoreFromState(47 createState({48 turn: 2,49 currentPlayer: "P1A",50 playerOrder: ["P1A", "P2A"],51 playerStateById: {52 P1A: {53 phase: "action",54 cardsOnHand: [createCard({ id: "C1A", cost: 7 })],55 },56 },57 })58 );59 const putDownCardOptions = { location: "zone", cardId: "C1A" };60 const error = catchError(() =>61 this.match.putDownCard("P1A", putDownCardOptions)62 );63 assert.equals(error.message, "Cannot afford card");64 assert.equals(error.type, "CheatDetected");65 },66 "when can afford card:": {67 async setUp() {68 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);69 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);70 this.match = createMatch({71 players: [72 createPlayer({ id: "P1A", connection: this.firstPlayerConnection }),73 createPlayer({ id: "P2A", connection: this.secondPlayerConnection }),74 ],75 });76 this.match.restoreFromState(77 createState({78 turn: 1,79 currentPlayer: "P1A",80 playerOrder: ["P1A", "P2A"],81 playerStateById: {82 P1A: {83 phase: "action",84 cardsOnHand: [createCard({ id: "C1A", cost: 1 })],85 stationCards: [86 { card: createCard({ id: "C2A" }), place: "action" },87 ],88 },89 },90 })91 );92 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" });93 },94 "should put card in zone"() {95 this.match.refresh("P1A");96 const state = this.firstPlayerConnection.stateChanged.firstCall.args[0];97 assert.equals(state.cardsInZone.length, 1);98 assert.equals(state.cardsInZone[0].id, "C1A");99 },100 "should remove card from hand"() {101 this.match.refresh("P1A");102 const state = this.firstPlayerConnection.stateChanged.firstCall.args[0];103 assert.equals(state.cardsOnHand.length, 0);104 },105 "should add event"() {106 this.match.refresh("P1A");107 const state = this.firstPlayerConnection.stateChanged.firstCall.args[0];108 assert.equals(state.events.length, 1);109 assert.match(state.events[0], {110 type: "putDownCard",111 turn: 1,112 location: "zone",113 cardId: "C1A",114 });115 },116 "when second player restore state should get zone card"() {117 this.match.refresh("P2A");118 const {119 opponentCardsInZone,120 } = this.secondPlayerConnection.stateChanged.lastCall.args[0];121 assert(opponentCardsInZone);122 assert.equals(opponentCardsInZone.length, 1);123 assert.match(opponentCardsInZone[0], { id: "C1A" });124 },125 },126 "when put down card in zone and card is already in zone": {127 async setUp() {128 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);129 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);130 this.match = createMatch({131 players: [132 createPlayer({ id: "P1A", connection: this.firstPlayerConnection }),133 createPlayer({ id: "P2A", connection: this.secondPlayerConnection }),134 ],135 });136 this.match.restoreFromState(137 createState({138 turn: 1,139 currentPlayer: "P1A",140 playerOrder: ["P1A", "P2A"],141 playerStateById: {142 P1A: {143 phase: "action",144 cardsOnHand: [],145 cardsInZone: [createCard({ id: "C1A", cost: 1 })],146 stationCards: [147 { card: createCard({ id: "C2A" }), place: "action" },148 ],149 },150 },151 })152 );153 this.error = catchError(() =>154 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" })155 );156 },157 "should only have one copy of the card in the zone"() {158 this.match.refresh("P1A");159 const state = this.firstPlayerConnection.stateChanged.firstCall.args[0];160 assert.equals(state.cardsInZone.length, 1);161 assert.equals(state.cardsInZone[0].id, "C1A");162 },163 "should NOT add an event"() {164 this.match.refresh("P1A");165 const state = this.firstPlayerConnection.stateChanged.firstCall.args[0];166 assert.equals(state.events.length, 0);167 },168 "should throw error"() {169 assert(this.error);170 assert.equals(this.error.message, "Card is already at location");171 },172 },173 "when put down card in station and card is in zone": {174 async setUp() {175 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);176 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);177 this.match = createMatch({178 players: [179 createPlayer({ id: "P1A", connection: this.firstPlayerConnection }),180 createPlayer({ id: "P2A", connection: this.secondPlayerConnection }),181 ],182 });183 this.match.restoreFromState(184 createState({185 turn: 1,186 currentPlayer: "P1A",187 playerOrder: ["P1A", "P2A"],188 playerStateById: {189 P1A: {190 phase: "action",191 cardsOnHand: [],192 cardsInZone: [createCard({ id: "C1A", cost: 1 })],193 stationCards: [194 { card: createCard({ id: "C2A" }), place: "action" },195 ],196 },197 },198 })199 );200 this.error = catchError(() =>201 this.match.putDownCard("P1A", {202 location: "station-action",203 cardId: "C1A",204 })205 );206 },207 "should only have one copy of the card in the zone"() {208 this.match.refresh("P1A");209 const state = this.firstPlayerConnection.stateChanged.firstCall.args[0];210 assert.equals(state.cardsInZone.length, 1);211 assert.equals(state.cardsInZone[0].id, "C1A");212 },213 "should NOT add an event"() {214 this.match.refresh("P1A");215 const state = this.firstPlayerConnection.stateChanged.firstCall.args[0];216 assert.equals(state.events.length, 0);217 },218 "should throw error"() {219 assert(this.error);220 assert.equals(221 this.error.message,222 "Cannot move card from zone to station"223 );224 },225 },226 "when put down station card and has already put down a station this turn should throw error": function () {227 const match = createMatch({228 players: [createPlayer({ id: "P1A" })],229 });230 match.restoreFromState(231 createState({232 playerStateById: {233 P1A: {234 phase: "action",235 cardsOnHand: [createCard({ id: "C1A" }), createCard({ id: "C2A" })],236 stationCards: [],237 },238 },239 })240 );241 match.putDownCard("P1A", { location: "station-draw", cardId: "C1A" });242 const error = catchError(() =>243 match.putDownCard("P1A", { location: "station-draw", cardId: "C2A" })244 );245 assert.equals(246 error.message,247 "Cannot put down more station cards this turn"248 );249 assert.equals(error.type, "CheatDetected");250 },251 "when put down card and is NOT your turn should throw error": function () {252 const match = createMatch({253 players: [createPlayer({ id: "P1A" })],254 });255 match.restoreFromState(256 createState({257 currentPlayer: "P1A",258 playerStateById: {259 P2A: {260 phase: "wait",261 cardsOnHand: [createCard({ id: "C2A" })],262 },263 },264 })265 );266 const error = catchError(() =>267 match.putDownCard("P2A", { location: "zone", cardId: "C2A" })268 );269 assert.equals(error.message, "Cannot put down card");270 assert.equals(error.type, "CheatDetected");271 },272 "when has 1 flipped action station card and put down that station card": {273 setUp() {274 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);275 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);276 this.match = createMatch({277 players: [278 Player("P1A", this.firstPlayerConnection),279 Player("P2A", this.secondPlayerConnection),280 ],281 });282 this.match.restoreFromState(283 createState({284 currentPlayer: "P1A",285 playerOrder: ["P1A", "P2A"],286 playerStateById: {287 P1A: {288 phase: "action",289 cardsInZone: [],290 stationCards: [291 { card: createCard({ id: "C1A" }), place: "action" },292 {293 flipped: true,294 card: createCard({ id: "C2A" }),295 place: "action",296 },297 ],298 },299 P2A: {},300 },301 })302 );303 this.match.putDownCard("P1A", { location: "zone", cardId: "C2A" });304 },305 "when restore state should have card on hand and not among station cards"() {306 this.match.refresh("P1A");307 const {308 stationCards,309 cardsInZone,310 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];311 assert.equals(stationCards.length, 1);312 assert.equals(stationCards[0].id, "C1A");313 assert.equals(cardsInZone.length, 1);314 assert.equals(cardsInZone[0].id, "C2A");315 },316 "when second player restore state the opponent should have 1 more card in play and 1 less action station card"() {317 this.match.refresh("P2A");318 const {319 opponentCardsInZone,320 opponentStationCards,321 } = this.secondPlayerConnection.stateChanged.lastCall.args[0];322 assert.equals(opponentCardsInZone.length, 1);323 assert.equals(opponentCardsInZone[0].id, "C2A");324 assert.equals(opponentStationCards.length, 1);325 assert.equals(opponentStationCards[0].id, "C1A");326 },327 },328 "when try to move flipped station card to zone but cannot afford card should throw"() {329 this.match = createMatch({ players: [Player("P1A"), Player("P2A")] });330 this.match.restoreFromState(331 createState({332 currentPlayer: "P1A",333 playerOrder: ["P1A", "P2A"],334 playerStateById: {335 P1A: {336 phase: "action",337 cardsInZone: [],338 stationCards: [339 { card: createCard({ id: "C1A" }), place: "action" },340 {341 flipped: true,342 card: createCard({ id: "C2A", cost: 5 }),343 place: "action",344 },345 ],346 },347 },348 })349 );350 const error = catchError(() =>351 this.match.putDownCard("P1A", { location: "zone", cardId: "C2A" })352 );353 assert(error);354 assert.equals(error.message, "Cannot afford card");355 },356 "when try to move station card that is NOT flipped to zone should throw"() {357 this.match = createMatch({ players: [Player("P1A"), Player("P2A")] });358 this.match.restoreFromState(359 createState({360 currentPlayer: "P1A",361 playerOrder: ["P1A", "P2A"],362 playerStateById: {363 P1A: {364 phase: "action",365 cardsInZone: [],366 stationCards: [367 { card: createCard({ id: "C1A" }), place: "action" },368 {369 flipped: false,370 card: createCard({ id: "C2A" }),371 place: "action",372 },373 ],374 },375 },376 })377 );378 const error = catchError(() =>379 this.match.putDownCard("P1A", { location: "zone", cardId: "C2A" })380 );381 assert(error);382 assert.equals(383 error.message,384 "Cannot move station card that is not flipped to zone"385 );386 },387 "when has 1 flipped event station card and put down that station card": {388 setUp() {389 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);390 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);391 this.match = createMatch({392 players: [393 Player("P1A", this.firstPlayerConnection),394 Player("P2A", this.secondPlayerConnection),395 ],396 });397 this.match.restoreFromState(398 createState({399 currentPlayer: "P1A",400 playerOrder: ["P1A", "P2A"],401 playerStateById: {402 P1A: {403 phase: "action",404 cardsInZone: [],405 stationCards: [406 { card: createCard({ id: "C1A" }), place: "action" },407 {408 flipped: true,409 card: createCard({ id: "C2A", type: "event" }),410 place: "action",411 },412 ],413 },414 },415 })416 );417 this.match.putDownCard("P1A", { location: "zone", cardId: "C2A" });418 },419 "first player should NOT have card among station cards"() {420 this.match.refresh("P1A");421 const {422 stationCards,423 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];424 assert.equals(stationCards.length, 1);425 assert.equals(stationCards[0].id, "C1A");426 },427 "first player should NOT have card in zone"() {428 this.match.refresh("P1A");429 const {430 cardsInZone,431 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];432 assert.equals(cardsInZone.length, 0);433 },434 "first player should have card in discard pile"() {435 this.match.refresh("P1A");436 const {437 discardedCards,438 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];439 assert.equals(discardedCards.length, 1);440 assert.equals(discardedCards[0].id, "C2A");441 },442 "when second player restore state the opponent should have 0 cards in play and 1 less action station card and 1 more card in discarded pile"() {443 this.match.refresh("P2A");444 const {445 opponentDiscardedCards,446 opponentCardsInZone,447 opponentStationCards,448 } = this.secondPlayerConnection.stateChanged.lastCall.args[0];449 assert.equals(opponentDiscardedCards.length, 1);450 assert.equals(opponentDiscardedCards[0].id, "C2A");451 assert.equals(opponentCardsInZone.length, 0);452 assert.equals(opponentStationCards.length, 1);453 assert.equals(opponentStationCards[0].id, "C1A");454 },455 "should emit state changed to second player"() {456 assert.calledOnce(this.secondPlayerConnection.stateChanged);457 assert.calledWith(458 this.secondPlayerConnection.stateChanged,459 sinon.match({460 opponentDiscardedCards: [sinon.match({ id: "C2A" })],461 })462 );463 },464 "should NOT emit state changed with opponentCardCount to second player"() {465 refute.defined(466 this.secondPlayerConnection.stateChanged.lastCall.args[0]467 .opponentCardCount468 );469 },470 "should NOT emit state changed with opponentCardsInZone to second player"() {471 refute.defined(472 this.secondPlayerConnection.stateChanged.lastCall.args[0]473 .opponentCardsInZone474 );475 },476 },477 "when put down event card from hand to own zone": {478 setUp() {479 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);480 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);481 const players = [482 Player("P1A", this.firstPlayerConnection),483 Player("P2A", this.secondPlayerConnection),484 ];485 this.match = createMatch({ players });486 this.match.restoreFromState(487 createState({488 playerStateById: {489 P1A: {490 phase: "action",491 cardsOnHand: [createCard({ id: "C1A", type: "event" })],492 },493 },494 })495 );496 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" });497 },498 "first player should have card in discard pile"() {499 this.match.refresh("P1A");500 const {501 discardedCards,502 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];503 assert.equals(discardedCards.length, 1);504 assert.match(discardedCards[0], { id: "C1A" });505 },506 "first player should NOT have card in zone"() {507 this.match.refresh("P1A");508 const {509 cardsInZone,510 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];511 assert.equals(cardsInZone.length, 0);512 },513 "first player should NOT have card on hand"() {514 this.match.refresh("P1A");515 const {516 cardsOnHand,517 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];518 assert.equals(cardsOnHand.length, 0);519 },520 "should emit state changed with opponent discarded cards and card count to second player"() {521 assert.calledOnce(this.secondPlayerConnection.stateChanged);522 assert.calledWith(523 this.secondPlayerConnection.stateChanged,524 sinon.match({525 opponentCardCount: 0,526 opponentDiscardedCards: [sinon.match({ id: "C1A" })],527 })528 );529 },530 },531 "Supernova:": {532 "when first player put down Supernova": {533 setUp() {534 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);535 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);536 const players = [537 Player("P1A", this.firstPlayerConnection),538 Player("P2A", this.secondPlayerConnection),539 ];540 this.match = createMatch({ players });541 this.match.restoreFromState(542 createState({543 playerStateById: {544 P1A: {545 phase: "action",546 cardsInZone: [createCard({ id: "C1A" })],547 cardsInOpponentZone: [createCard({ id: "C2A" })],548 cardsOnHand: [549 createCard({550 id: "C3A",551 type: "event",552 commonId: SupernovaCommonId,553 }),554 createCard({ id: "A" }),555 createCard({ id: "B" }),556 createCard({ id: "C" }),557 ],558 stationCards: [559 { card: createCard({ id: "S1A" }), place: "action" },560 { card: createCard({ id: "S2A" }), place: "action" },561 { card: createCard({ id: "S3A" }), place: "action" },562 { card: createCard({ id: "S3A" }), place: "action" },563 ],564 },565 P2A: {566 phase: "wait",567 cardsInZone: [createCard({ id: "C4A" })],568 cardsInOpponentZone: [createCard({ id: "C5A" })],569 cardsOnHand: [570 createCard({ id: "D" }),571 createCard({ id: "E" }),572 createCard({ id: "F" }),573 ],574 stationCards: [575 { card: createCard({ id: "S4A" }), place: "action" },576 { card: createCard({ id: "S5A" }), place: "action" },577 { card: createCard({ id: "S6A" }), place: "action" },578 ],579 },580 },581 })582 );583 this.match.putDownCard("P1A", { location: "zone", cardId: "C3A" });584 },585 "should emit stateChanged to first player"() {586 assert.calledOnce(this.firstPlayerConnection.stateChanged);587 assert.calledWith(588 this.firstPlayerConnection.stateChanged,589 sinon.match({590 cardsInZone: [],591 cardsInOpponentZone: [],592 opponentCardsInZone: [],593 opponentCardsInPlayerZone: [],594 discardedCards: [595 sinon.match({ id: "C1A" }),596 sinon.match({ id: "C2A" }),597 sinon.match({ id: "C3A" }),598 ],599 opponentDiscardedCards: [600 sinon.match({ id: "C4A" }),601 sinon.match({ id: "C5A" }),602 ],603 requirements: [604 sinon.match({605 type: "damageStationCard",606 common: true,607 count: 3,608 }),609 ],610 events: [611 sinon.match({ type: "discardCard", cardId: "C1A" }),612 sinon.match({ type: "discardCard", cardId: "C2A" }),613 sinon.match({ type: "putDownCard", cardId: "C3A" }),614 sinon.match({ type: "discardCard", cardId: "C3A" }),615 ],616 })617 );618 },619 "should emit stateChanged to second player"() {620 assert.calledOnce(this.secondPlayerConnection.stateChanged);621 assert.calledWith(622 this.secondPlayerConnection.stateChanged,623 sinon.match({624 cardsInZone: [],625 cardsInOpponentZone: [],626 opponentCardsInZone: [],627 opponentCardsInPlayerZone: [],628 discardedCards: [629 sinon.match({ id: "C4A" }),630 sinon.match({ id: "C5A" }),631 ],632 opponentDiscardedCards: [633 sinon.match({ id: "C1A" }),634 sinon.match({ id: "C2A" }),635 sinon.match({ id: "C3A" }),636 ],637 opponentCardCount: 3,638 events: [639 sinon.match({ type: "discardCard", cardId: "C4A" }),640 sinon.match({ type: "discardCard", cardId: "C5A" }),641 ],642 requirements: [643 sinon.match({644 type: "damageStationCard",645 common: true,646 count: 3,647 }),648 ],649 })650 );651 },652 },653 "when first player put down Supernova and both players has NO station cards": {654 setUp() {655 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);656 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);657 const players = [658 Player("P1A", this.firstPlayerConnection),659 Player("P2A", this.secondPlayerConnection),660 ];661 this.match = createMatch({ players });662 this.match.restoreFromState(663 createState({664 playerStateById: {665 P1A: {666 phase: "action",667 cardsOnHand: [668 createCard({669 id: "C3A",670 type: "event",671 commonId: SupernovaCommonId,672 }),673 ],674 stationCards: [],675 },676 P2A: {677 stationCards: [],678 },679 },680 })681 );682 },683 "should Throw Cannot put down card error of type CheatDetected"() {684 const error = catchError(() =>685 this.match.putDownCard("P1A", { location: "zone", cardId: "C3A" })686 );687 assert.equals(error.message, "Cannot put down card");688 assert.equals(error.type, "CheatDetected");689 },690 },691 "when first player put down Supernova and both players has 1 flipped station card and 1 unflipped station card": {692 setUp() {693 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);694 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);695 const players = [696 Player("P1A", this.firstPlayerConnection),697 Player("P2A", this.secondPlayerConnection),698 ];699 this.match = createMatch({ players });700 this.match.restoreFromState(701 createState({702 playerStateById: {703 P1A: {704 phase: "action",705 cardsOnHand: [706 createCard({707 id: "C1A",708 type: "event",709 commonId: SupernovaCommonId,710 }),711 ],712 stationCards: [713 { card: createCard({ id: "C2A" }), place: "draw" },714 {715 flipped: true,716 card: createCard({ id: "C3A" }),717 place: "draw",718 },719 ],720 },721 P2A: {722 stationCards: [723 { card: createCard({ id: "C4A" }), place: "draw" },724 {725 flipped: true,726 card: createCard({ id: "C5A" }),727 place: "draw",728 },729 ],730 },731 },732 })733 );734 },735 "should Throw Cannot put down card error of type CheatDetected"() {736 const error = catchError(() =>737 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" })738 );739 assert.equals(error.message, "Cannot put down card");740 assert.equals(error.type, "CheatDetected");741 },742 },743 },744 "Excellent work": {745 "when first player put down Excellent work": {746 setUp() {747 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);748 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);749 const players = [750 Player("P1A", this.firstPlayerConnection),751 Player("P2A", this.secondPlayerConnection),752 ];753 this.match = createMatch({ players });754 this.match.restoreFromState(755 createState({756 playerStateById: {757 P1A: {758 phase: "action",759 cardsOnHand: [760 createCard({761 id: "C1A",762 type: "event",763 commonId: ExcellentWorkCommonId,764 }),765 ],766 cardsInDeck: [767 createCard({ id: "C2A" }),768 createCard({ id: "C3A" }),769 createCard({ id: "C4A" }),770 ],771 },772 },773 })774 );775 this.match.putDownCard("P1A", {776 location: "zone",777 cardId: "C1A",778 choice: "draw",779 });780 },781 "first player should get discarded cards"() {782 assert.calledWith(783 this.firstPlayerConnection.stateChanged,784 sinon.match({785 discardedCards: [sinon.match({ id: "C1A" })],786 })787 );788 },789 "first player should get events"() {790 assert.calledWith(791 this.firstPlayerConnection.stateChanged,792 sinon.match({793 events: [794 sinon.match({ type: "putDownCard", cardId: "C1A" }),795 sinon.match({ type: "discardCard", cardId: "C1A" }),796 ],797 })798 );799 },800 "first player should get new requirement"() {801 assert.calledWith(802 this.firstPlayerConnection.stateChanged,803 sinon.match({804 requirements: [sinon.match({ type: "drawCard", count: 3 })],805 })806 );807 },808 "second player should get opponent card count"() {809 assert.calledWith(810 this.secondPlayerConnection.stateChanged,811 sinon.match({812 opponentCardCount: 0,813 })814 );815 },816 "second player should opponent discarded cards"() {817 assert.calledWith(818 this.secondPlayerConnection.stateChanged,819 sinon.match({820 opponentDiscardedCards: [sinon.match({ id: "C1A" })],821 })822 );823 },824 },825 "when first player put down Excellent work but only has 1 card left in deck": {826 setUp() {827 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);828 this.match = createMatch({829 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],830 });831 this.match.restoreFromState(832 createState({833 playerStateById: {834 P1A: {835 phase: "action",836 cardsOnHand: [837 createCard({838 id: "C1A",839 type: "event",840 commonId: ExcellentWorkCommonId,841 }),842 ],843 cardsInDeck: [createCard({ id: "C2A" })],844 },845 },846 })847 );848 this.match.putDownCard("P1A", {849 location: "zone",850 cardId: "C1A",851 choice: "draw",852 });853 },854 "should emit stateChanged to first player with requirement count of 1"() {855 assert.calledOnce(this.firstPlayerConnection.stateChanged);856 assert.calledWith(857 this.firstPlayerConnection.stateChanged,858 sinon.match({859 requirements: [sinon.match({ type: "drawCard", count: 1 })],860 })861 );862 },863 },864 "when first player put down Excellent work but has NO card left in deck": {865 setUp() {866 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);867 this.match = createMatch({868 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],869 });870 this.match.restoreFromState(871 createState({872 playerStateById: {873 P1A: {874 phase: "action",875 cardsOnHand: [876 createCard({877 id: "C1A",878 type: "event",879 commonId: ExcellentWorkCommonId,880 }),881 ],882 cardsInDeck: [],883 },884 },885 })886 );887 this.match.putDownCard("P1A", {888 location: "zone",889 cardId: "C1A",890 choice: "draw",891 });892 },893 "should emit state changed with not requirements"() {894 assert.calledWith(895 this.firstPlayerConnection.stateChanged,896 sinon.match({897 requirements: [],898 })899 );900 },901 },902 "when has already put down station card this turn and put down Excellent work": {903 setUp() {904 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);905 const players = [Player("P1A", this.firstPlayerConnection)];906 this.match = createMatch({ players });907 this.match.restoreFromState(908 createState({909 playerStateById: {910 P1A: {911 turn: 1,912 phase: "action",913 cardsOnHand: [914 createCard({ id: "C2A", commonId: ExcellentWorkCommonId }),915 ],916 stationCards: [917 { place: "draw", id: "C1A", card: createCard({ id: "C1A" }) },918 ],919 events: [920 PutDownCardEvent({921 turn: 1,922 location: "station-draw",923 cardId: "C1A",924 }),925 ],926 },927 },928 })929 );930 const options = {931 location: "station-draw",932 cardId: "C2A",933 choice: "draw",934 };935 this.error = catchError(() => this.match.putDownCard("P1A", options));936 },937 "should NOT throw"() {938 refute(this.error);939 },940 "should have added excellent work as station card"() {941 this.match.refresh("P1A");942 assert.calledWith(943 this.firstPlayerConnection.stateChanged,944 sinon.match({945 stationCards: [946 sinon.match({ id: "C1A", place: "draw" }),947 sinon.match({ id: "C2A", place: "draw" }),948 ],949 })950 );951 },952 },953 "when put down excellent work as extra station card and then put down another card as station card": {954 setUp() {955 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);956 const players = [Player("P1A", this.firstPlayerConnection)];957 this.match = createMatch({ players });958 this.match.restoreFromState(959 createState({960 playerStateById: {961 P1A: {962 turn: 1,963 phase: "action",964 cardsOnHand: [965 createCard({ id: "C1A", commonId: ExcellentWorkCommonId }),966 createCard({ id: "C2A" }),967 ],968 stationCards: [],969 events: [],970 },971 },972 })973 );974 this.match.putDownCard("P1A", {975 location: "station-draw",976 cardId: "C1A",977 choice: "putDownAsExtraStationCard",978 });979 const options = { location: "station-draw", cardId: "C2A" };980 this.error = catchError(() => this.match.putDownCard("P1A", options));981 },982 "should NOT throw"() {983 refute(this.error);984 },985 "should have added card as station card"() {986 this.match.refresh("P1A");987 assert.calledWith(988 this.firstPlayerConnection.stateChanged,989 sinon.match({990 stationCards: [991 sinon.match({ id: "C1A", place: "draw" }),992 sinon.match({ id: "C2A", place: "draw" }),993 ],994 })995 );996 },997 },998 "when put down excellent work but NOT as extra station card and then put down another card as station card": {999 setUp() {1000 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1001 const players = [Player("P1A", this.firstPlayerConnection)];1002 this.match = createMatch({ players });1003 this.match.restoreFromState(1004 createState({1005 playerStateById: {1006 P1A: {1007 turn: 1,1008 phase: "action",1009 cardsOnHand: [1010 createCard({ id: "C1A", commonId: ExcellentWorkCommonId }),1011 createCard({ id: "C2A" }),1012 ],1013 stationCards: [1014 { card: createCard({ id: "S1A" }), place: "action" },1015 ],1016 },1017 },1018 })1019 );1020 this.match.putDownCard("P1A", {1021 location: "station-draw",1022 cardId: "C1A",1023 });1024 const options = { location: "station-draw", cardId: "C2A" };1025 this.error = catchError(() => this.match.putDownCard("P1A", options));1026 },1027 "should throw"() {1028 assert(this.error);1029 assert.equals(1030 this.error.message,1031 "Cannot put down more station cards this turn"1032 );1033 },1034 "should NOT have added card as station card"() {1035 this.match.refresh("P1A");1036 assert.calledWith(1037 this.firstPlayerConnection.stateChanged,1038 sinon.match({1039 stationCards: [1040 sinon.match({ id: "S1A" }),1041 sinon.match({ id: "C1A", place: "draw" }),1042 ],1043 })1044 );1045 },1046 },1047 "when excellent work is in draw station row and is then moved to action station row": {1048 setUp() {1049 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1050 const players = [Player("P1A", this.firstPlayerConnection)];1051 this.match = createMatch({ players });1052 this.match.restoreFromState(1053 createState({1054 playerStateById: {1055 P1A: {1056 turn: 1,1057 phase: "action",1058 stationCards: [1059 { id: "C1A", place: "draw", card: createCard({ id: "C1A" }) },1060 {1061 id: "C2A",1062 place: "draw",1063 flipped: true,1064 card: createCard({1065 id: "C2A",1066 commonId: ExcellentWorkCommonId,1067 }),1068 },1069 ],1070 events: [],1071 },1072 },1073 })1074 );1075 const options = { location: "station-action", cardId: "C2A" };1076 this.error = catchError(() => this.match.putDownCard("P1A", options));1077 },1078 "should NOT throw"() {1079 refute(this.error);1080 },1081 "should have moved station card"() {1082 this.match.refresh("P1A");1083 assert.calledWith(1084 this.firstPlayerConnection.stateChanged,1085 sinon.match({1086 stationCards: [1087 sinon.match({ id: "C1A", place: "draw" }),1088 sinon.match({ id: "C2A", place: "action" }),1089 ],1090 })1091 );1092 },1093 },1094 },1095 "Grand Opportunity": {1096 "when first player put down Grand Opportunity": {1097 setUp() {1098 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1099 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);1100 const players = [1101 Player("P1A", this.firstPlayerConnection),1102 Player("P2A", this.secondPlayerConnection),1103 ];1104 this.match = createMatch({ players });1105 this.match.restoreFromState(1106 createState({1107 playerStateById: {1108 P1A: {1109 phase: "action",1110 cardsOnHand: [1111 createCard({1112 id: "C1A",1113 type: "event",1114 commonId: GrandOpportunityCommonId,1115 }),1116 createCard({1117 id: "C2A",1118 type: "event",1119 commonId: GrandOpportunityCommonId,1120 }),1121 createCard({1122 id: "C3A",1123 type: "event",1124 commonId: GrandOpportunityCommonId,1125 }),1126 ],1127 cardsInDeck: [1128 createCard({ id: "C4A" }),1129 createCard({ id: "C5A" }),1130 createCard({ id: "C6A" }),1131 createCard({ id: "C7A" }),1132 createCard({ id: "C8A" }),1133 createCard({ id: "C9A" }),1134 ],1135 },1136 },1137 })1138 );1139 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" });1140 },1141 "should emit stateChanged to first player"() {1142 assert.calledOnce(this.firstPlayerConnection.stateChanged);1143 assert.calledWith(1144 this.firstPlayerConnection.stateChanged,1145 sinon.match({1146 discardedCards: [sinon.match({ id: "C1A" })],1147 requirements: [1148 sinon.match({ type: "drawCard", count: sinon.match.number }),1149 sinon.match({ type: "discardCard", count: sinon.match.number }),1150 ],1151 events: [1152 sinon.match({ type: "putDownCard", cardId: "C1A" }),1153 sinon.match({ type: "discardCard", cardId: "C1A" }),1154 ],1155 })1156 );1157 },1158 "should emit stateChanged to second player"() {1159 assert.calledOnce(this.secondPlayerConnection.stateChanged);1160 assert.calledWith(1161 this.secondPlayerConnection.stateChanged,1162 sinon.match({1163 opponentDiscardedCards: [sinon.match({ id: "C1A" })],1164 opponentCardCount: 2,1165 })1166 );1167 },1168 },1169 "when first player put down Grand Opportunity but only has 1 card left in deck and 1 more on hand": {1170 setUp() {1171 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1172 this.match = createMatch({1173 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],1174 });1175 this.match.restoreFromState(1176 createState({1177 playerStateById: {1178 P1A: {1179 phase: "action",1180 cardsOnHand: [1181 createCard({1182 id: "C1A",1183 type: "event",1184 commonId: GrandOpportunityCommonId,1185 }),1186 createCard({ id: "C2A" }),1187 ],1188 cardsInDeck: [createCard({ id: "C3A" })],1189 },1190 },1191 })1192 );1193 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" });1194 },1195 "should emit stateChanged to first player with draw card of count of 1 and discard card of count 1"() {1196 assert.calledOnce(this.firstPlayerConnection.stateChanged);1197 assert.calledWith(1198 this.firstPlayerConnection.stateChanged,1199 sinon.match({1200 requirements: [1201 sinon.match({ type: "drawCard", count: 1 }),1202 sinon.match({ type: "discardCard", count: 1 }),1203 ],1204 })1205 );1206 },1207 },1208 "when first player put down Grand Opportunity but only has NO card left in deck and 1 more on hand": {1209 setUp() {1210 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1211 this.match = createMatch({1212 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],1213 });1214 this.match.restoreFromState(1215 createState({1216 playerStateById: {1217 P1A: {1218 phase: "action",1219 cardsOnHand: [1220 createCard({1221 id: "C1A",1222 type: "event",1223 commonId: GrandOpportunityCommonId,1224 }),1225 createCard({ id: "C2A" }),1226 ],1227 cardsInDeck: [],1228 },1229 },1230 })1231 );1232 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" });1233 },1234 "should emit stateChanged to first player with ONLY discard card"() {1235 assert.calledOnce(this.firstPlayerConnection.stateChanged);1236 assert.calledWith(1237 this.firstPlayerConnection.stateChanged,1238 sinon.match({1239 requirements: [sinon.match({ type: "discardCard", count: 1 })],1240 })1241 );1242 },1243 },1244 "when first player put down Grand Opportunity but only has 1 card left in deck and NO more on hand": {1245 setUp() {1246 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1247 this.match = createMatch({1248 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],1249 });1250 this.match.restoreFromState(1251 createState({1252 playerStateById: {1253 P1A: {1254 phase: "action",1255 cardsOnHand: [1256 createCard({1257 id: "C1A",1258 type: "event",1259 commonId: GrandOpportunityCommonId,1260 }),1261 ],1262 cardsInDeck: [createCard({ id: "C2A" })],1263 },1264 },1265 })1266 );1267 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" });1268 },1269 "should emit draw card requirement of count 1"() {1270 assert.calledOnce(this.firstPlayerConnection.stateChanged);1271 assert.calledWith(1272 this.firstPlayerConnection.stateChanged,1273 sinon.match({1274 requirements: [sinon.match({ type: "drawCard", count: 1 })],1275 })1276 );1277 },1278 },1279 },1280 "Discovery:": {1281 'when put down Discovery with choice "draw"': {1282 setUp() {1283 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1284 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);1285 const players = [1286 Player("P1A", this.firstPlayerConnection),1287 Player("P2A", this.secondPlayerConnection),1288 ];1289 this.match = createMatch({ players });1290 this.match.restoreFromState(1291 createState({1292 playerStateById: {1293 P1A: {1294 phase: "action",1295 cardsOnHand: [1296 createCard({1297 id: "C1A",1298 type: "event",1299 commonId: DiscoveryCommonId,1300 }),1301 ],1302 cardsInDeck: [1303 createCard({ id: "C4A" }),1304 createCard({ id: "C5A" }),1305 createCard({ id: "C6A" }),1306 createCard({ id: "C6A" }),1307 ],1308 },1309 P2A: {1310 cardsInDeck: [1311 createCard({ id: "C7A" }),1312 createCard({ id: "C8A" }),1313 createCard({ id: "C9A" }),1314 createCard({ id: "C10A" }),1315 ],1316 },1317 },1318 })1319 );1320 this.match.putDownCard("P1A", {1321 location: "zone",1322 cardId: "C1A",1323 choice: "draw",1324 });1325 },1326 "should emit stateChanged to first player"() {1327 assert.calledOnce(this.firstPlayerConnection.stateChanged);1328 assert.calledWith(1329 this.firstPlayerConnection.stateChanged,1330 sinon.match({1331 discardedCards: [sinon.match({ id: "C1A" })],1332 requirements: [1333 sinon.match({1334 type: "drawCard",1335 count: sinon.match.number,1336 common: true,1337 }),1338 ],1339 events: [1340 sinon.match({ type: "putDownCard", cardId: "C1A" }),1341 sinon.match({ type: "discardCard", cardId: "C1A" }),1342 ],1343 })1344 );1345 },1346 "should emit stateChanged to second player"() {1347 assert.calledOnce(this.secondPlayerConnection.stateChanged);1348 assert.calledWith(1349 this.secondPlayerConnection.stateChanged,1350 sinon.match({1351 opponentDiscardedCards: [sinon.match({ id: "C1A" })],1352 opponentCardCount: 0,1353 requirements: [1354 sinon.match({1355 type: "drawCard",1356 count: sinon.match.number,1357 common: true,1358 }),1359 ],1360 })1361 );1362 },1363 },1364 'when put down Discovery with choice "draw" but both players has NO cards left': {1365 setUp() {1366 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1367 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);1368 const players = [1369 Player("P1A", this.firstPlayerConnection),1370 Player("P2A", this.secondPlayerConnection),1371 ];1372 this.match = createMatch({ players });1373 this.match.restoreFromState(1374 createState({1375 playerStateById: {1376 P1A: {1377 phase: "action",1378 cardsOnHand: [1379 createCard({1380 id: "C1A",1381 type: "event",1382 commonId: DiscoveryCommonId,1383 }),1384 ],1385 cardsInDeck: [],1386 },1387 P2A: {1388 cardsInDeck: [],1389 },1390 },1391 })1392 );1393 this.match.putDownCard("P1A", {1394 location: "zone",1395 cardId: "C1A",1396 choice: "draw",1397 });1398 },1399 "first player should NOT have any requirements"() {1400 this.match.refresh("P1A");1401 assert.calledWith(1402 this.firstPlayerConnection.stateChanged,1403 sinon.match({1404 requirements: [],1405 })1406 );1407 },1408 "second player should NOT have any requirements"() {1409 this.match.refresh("P2A");1410 assert.calledWith(1411 this.secondPlayerConnection.stateChanged,1412 sinon.match({1413 requirements: [],1414 })1415 );1416 },1417 },1418 'when put down Discovery with choice "discard"': {1419 setUp() {1420 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1421 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);1422 const players = [1423 Player("P1A", this.firstPlayerConnection),1424 Player("P2A", this.secondPlayerConnection),1425 ];1426 this.match = createMatch({ players });1427 this.match.restoreFromState(1428 createState({1429 playerStateById: {1430 P1A: {1431 phase: "action",1432 cardsOnHand: [1433 createCard({1434 id: "C1A",1435 type: "event",1436 commonId: DiscoveryCommonId,1437 }),1438 createCard({ id: "C2A" }),1439 createCard({ id: "C3A" }),1440 ],1441 },1442 P2A: {1443 cardsOnHand: [1444 createCard({ id: "C4A" }),1445 createCard({ id: "C5A" }),1446 ],1447 },1448 },1449 })1450 );1451 this.match.putDownCard("P1A", {1452 location: "zone",1453 cardId: "C1A",1454 choice: "discard",1455 });1456 },1457 "should emit stateChanged to first player"() {1458 assert.calledOnce(this.firstPlayerConnection.stateChanged);1459 assert.calledWith(1460 this.firstPlayerConnection.stateChanged,1461 sinon.match({1462 requirements: [1463 sinon.match({1464 type: "discardCard",1465 count: sinon.match.number,1466 common: true,1467 }),1468 ],1469 })1470 );1471 },1472 "should emit stateChanged to second player"() {1473 assert.calledOnce(this.secondPlayerConnection.stateChanged);1474 assert.calledWith(1475 this.secondPlayerConnection.stateChanged,1476 sinon.match({1477 requirements: [1478 sinon.match({1479 type: "discardCard",1480 count: sinon.match.number,1481 common: true,1482 }),1483 ],1484 })1485 );1486 },1487 },1488 },1489 "Fatal Error:": {1490 "when move Fatal Error from station card to zone": {1491 setUp() {1492 const firstPlayerConnection = FakeConnection2(["stateChanged"]);1493 const players = [Player("P1A", firstPlayerConnection), Player("P2A")];1494 this.match = createMatch({ players });1495 this.firstPlayerAsserter = StateAsserter(1496 this.match,1497 firstPlayerConnection,1498 "P1A"1499 );1500 this.match.restoreFromState(1501 createState({1502 playerStateById: {1503 P1A: {1504 phase: "action",1505 stationCards: [1506 {1507 place: "action",1508 card: createCard({1509 id: "C1A",1510 type: "event",1511 commonId: FatalErrorCommonId,1512 }),1513 flipped: true,1514 },1515 ],1516 },1517 P2A: {1518 cardsInOpponentZone: [1519 createCard({ id: "C2A", commonId: "C2B" }),1520 ],1521 cardsInDeck: [1522 createCard({ id: "C3A" }),1523 createCard({ id: "C4A" }),1524 ],1525 },1526 },1527 })1528 );1529 this.match.putDownCard("P1A", {1530 location: "zone",1531 cardId: "C1A",1532 choice: "C2A",1533 });1534 },1535 "should emit FatalErrorUsed event to player"() {1536 this.firstPlayerAsserter.hasEvent((event) => {1537 return (1538 event.type === "fatalErrorUsed" &&1539 event.targetCardCommonId === "C2B"1540 );1541 });1542 },1543 },1544 "when put down Fatal Error with choice matching opponent card": {1545 setUp() {1546 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);1547 const players = [1548 Player("P1A"),1549 Player("P2A", this.secondPlayerConnection),1550 ];1551 this.match = createMatch({ players });1552 this.match.restoreFromState(1553 createState({1554 playerStateById: {1555 P1A: {1556 phase: "action",1557 cardsOnHand: [1558 createCard({1559 id: "C1A",1560 type: "event",1561 commonId: FatalErrorCommonId,1562 }),1563 ],1564 stationCards: [1565 { card: createCard({ id: "S1A" }), place: "action" },1566 ],1567 },1568 P2A: {1569 cardsInOpponentZone: [createCard({ id: "C2A", cost: 1 })],1570 },1571 },1572 })1573 );1574 this.match.putDownCard("P1A", {1575 location: "zone",1576 cardId: "C1A",1577 choice: "C2A",1578 });1579 },1580 "should emit card moved to discard pile for second player"() {1581 assert.calledOnce(this.secondPlayerConnection.stateChanged);1582 assert.calledWith(1583 this.secondPlayerConnection.stateChanged,1584 sinon.match({1585 cardsInOpponentZone: [],1586 discardedCards: [sinon.match({ id: "C2A" })],1587 })1588 );1589 },1590 },1591 "when put down Fatal Error with invalid card id as choice": {1592 setUp() {1593 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);1594 const players = [1595 Player("P1A"),1596 Player("P2A", this.secondPlayerConnection),1597 ];1598 this.match = createMatch({ players });1599 this.match.restoreFromState(1600 createState({1601 playerStateById: {1602 P1A: {1603 phase: "action",1604 cardsOnHand: [1605 createCard({1606 id: "C1A",1607 type: "event",1608 commonId: FatalErrorCommonId,1609 }),1610 ],1611 },1612 P2A: {1613 cardsInOpponentZone: [createCard({ id: "C2A", defense: 1 })],1614 },1615 },1616 })1617 );1618 this.error = catchError(() =>1619 this.match.putDownCard("P1A", {1620 location: "zone",1621 cardId: "C1A",1622 choice: null,1623 })1624 );1625 },1626 "should throw error"() {1627 assert(this.error);1628 assert.equals(this.error.message, "Cannot put down card");1629 },1630 },1631 },1632 "when put down Missiles launched": {1633 async setUp() {1634 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);1635 const players = [Player("P1A", this.firstPlayerConnection)];1636 this.match = createMatch(1637 { players },1638 {1639 regular: [{ id: MissilesLaunched.CommonId, price: "1" }],1640 theSwarm: [],1641 }1642 );1643 this.match.restoreFromState(1644 createState({1645 turn: 1,1646 playerStateById: {1647 P1A: {1648 phase: "action",1649 cardsOnHand: [1650 createCard({1651 id: "C1A",1652 type: "event",1653 commonId: MissilesLaunched.CommonId,1654 }),1655 ],1656 discardedCards: [createCard({ id: "C2A", type: "missile" })],1657 cardsInDeck: [createCard({ id: "C3A", type: "missile" })],1658 },1659 },1660 })1661 );1662 this.match.putDownCard("P1A", { location: "zone", cardId: "C1A" });1663 },1664 "should add requirement"() {1665 this.match.refresh("P1A");1666 assert.calledWith(1667 this.firstPlayerConnection.stateChanged,1668 sinon.match({1669 requirements: [1670 sinon.match({1671 cardGroups: [1672 sinon.match({ source: "deck", cards: [sinon.match.any] }),1673 sinon.match({1674 source: "discardPile",1675 cards: [sinon.match.any],1676 }),1677 ],1678 }),1679 ],1680 })1681 );1682 },1683 },1684 "Sabotage:": {1685 setUp() {1686 const firstPlayerConnection = FakeConnection2(["stateChanged"]);1687 const secondPlayerConnection = FakeConnection2(["stateChanged"]);1688 const players = [1689 Player("P1A", firstPlayerConnection),1690 Player("P2A", secondPlayerConnection),1691 ];1692 this.match = createMatch({ players });1693 this.firstPlayerAsserter = StateAsserter(1694 this.match,1695 firstPlayerConnection,1696 "P1A"1697 );1698 this.secondPlayerAsserter = StateAsserter(1699 this.match,1700 secondPlayerConnection,1701 "P2A"1702 );1703 },1704 "when put down sabotage on own turn in action phase": {1705 setUp() {1706 this.match.restoreFromState(1707 createState({1708 turn: 1,1709 playerStateById: {1710 P1A: {1711 phase: "action",1712 cardsOnHand: [1713 createCard({1714 id: "C1A",1715 type: "event",1716 commonId: Sabotage.CommonId,1717 }),1718 ],1719 },1720 P2A: {1721 phase: "wait",1722 cardsOnHand: [createCard({ id: "C2A" })],1723 cardsInDeck: [createCard({ id: "C3A" })],1724 },1725 },1726 })1727 );1728 this.match.putDownCard("P1A", {1729 location: "zone",1730 cardId: "C1A",1731 choice: null,1732 });1733 },1734 "should add requirement to player"() {1735 this.firstPlayerAsserter.hasRequirement({1736 type: "drawCard",1737 count: 0,1738 common: true,1739 waiting: true,1740 });1741 },1742 "should add requirement to opponent"() {1743 this.secondPlayerAsserter.hasRequirement({1744 type: "drawCard",1745 count: 1,1746 common: true,1747 });1748 },1749 "should NOT add find card requirement to player"() {1750 this.firstPlayerAsserter.refuteHasRequirement({ type: "findCard" });1751 },1752 },1753 "when has put down sabotage and opponent resolves draw card requirement": {1754 setUp() {1755 this.match.restoreFromState(1756 createState({1757 turn: 1,1758 playerStateById: {1759 P1A: {1760 phase: "action",1761 cardsOnHand: [1762 createCard({1763 id: "C1A",1764 type: "event",1765 commonId: Sabotage.CommonId,1766 }),1767 ],1768 },1769 P2A: {1770 phase: "wait",1771 cardsOnHand: [createCard({ id: "C2A" })],1772 cardsInDeck: [createCard({ id: "C3A" })],1773 },1774 },1775 })1776 );1777 this.match.putDownCard("P1A", {1778 location: "zone",1779 cardId: "C1A",1780 choice: null,1781 });1782 this.match.drawCard("P2A");1783 },1784 "should add find card requirement to player"() {1785 this.firstPlayerAsserter.hasRequirement({ type: "findCard" });1786 },1787 },1788 },...

Full Screen

Full Screen

remoteparticipant.js

Source:remoteparticipant.js Github

copy

Full Screen

1'use strict';2const assert = require('assert');3const sinon = require('sinon');4const RemoteParticipantV2 = require('../../../../../lib/signaling/v2/remoteparticipant');5const { defer } = require('../../../../../lib/util');6describe('RemoteParticipantV2', () => {7 // RemoteParticipantV28 // -------------------9 describe('constructor', () => {10 it('sets .identity', () => {11 const test = makeTest();12 assert.equal(test.identity, test.participant.identity);13 });14 it('sets .revision', () => {15 const test = makeTest();16 assert.equal(test.revision, test.participant.revision);17 });18 it('sets .sid', () => {19 const test = makeTest();20 assert.equal(test.sid, test.participant.sid);21 });22 it('sets .state to "connected"', () => {23 const test = makeTest();24 assert.equal('connected', test.participant.state);25 });26 context('.tracks', () => {27 it('constructs a new RemoteTrackPublicationV2 from each trackState', () => {28 const sid1 = makeSid();29 const sid2 = makeSid();30 const test = makeTest({31 tracks: [32 { sid: sid1 },33 { sid: sid2 }34 ]35 });36 assert.equal(sid1, test.remoteTrackPublicationV2s[0].sid);37 assert.equal(sid2, test.remoteTrackPublicationV2s[1].sid);38 });39 it('adds the newly-constructed RemoteTrackPublicationV2s to the RemoteParticipantV2\'s .tracks Map', () => {40 const sid1 = makeSid();41 const sid2 = makeSid();42 const test = makeTest({43 tracks: [44 { sid: sid1 },45 { sid: sid2 }46 ]47 });48 assert.equal(49 test.remoteTrackPublicationV2s[0],50 test.participant.tracks.get(sid1));51 assert.equal(52 test.remoteTrackPublicationV2s[1],53 test.participant.tracks.get(sid2));54 });55 });56 });57 describe('#update, when called with a participantState at', () => {58 context('a newer revision', () => {59 it('returns the RemoteParticipantV2', () => {60 const test = makeTest();61 const participantState = test.state(test.revision + 1);62 assert.equal(63 test.participant,64 test.participant.update(participantState));65 });66 it('updates the .revision', () => {67 const test = makeTest();68 const participantState = test.state(test.revision + 1);69 test.participant.update(participantState);70 assert.equal(71 test.revision + 1,72 test.participant.revision);73 });74 context('which includes a new trackState not matching an existing RemoteTrackPublicationV2', () => {75 it('constructs a new RemoteTrackPublicationV2 from the trackState', () => {76 const test = makeTest();77 const sid = makeSid();78 const participantState = test.state(test.revision + 1).setTrack({ sid });79 test.participant.update(participantState);80 assert.equal(sid, test.remoteTrackPublicationV2s[0].sid);81 });82 it('adds the newly-constructed RemoteTrackPublicationV2 to the RemoteParticipantV2\'s .tracks Map', () => {83 const test = makeTest();84 const sid = makeSid();85 const participantState = test.state(test.revision + 1).setTrack({ sid });86 test.participant.update(participantState);87 assert.equal(88 test.remoteTrackPublicationV2s[0],89 test.participant.tracks.get(sid));90 });91 it('emits the "trackAdded" event with the newly-constructed RemoteTrackPublicationV2', () => {92 const test = makeTest();93 const participantState = test.state(test.revision + 1).setTrack({ id: makeSid() });94 let track;95 test.participant.once('trackAdded', _track => { track = _track; });96 test.participant.update(participantState);97 assert.equal(98 test.remoteTrackPublicationV2s[0],99 track);100 });101 it('calls update with the trackState on the newly-constructed RemoteTrackPublicationV2', () => {102 const test = makeTest();103 const sid = makeSid();104 const participantState = test.state(test.revision + 1).setTrack({ sid, fizz: 'buzz' });105 test.participant.update(participantState);106 assert.deepEqual(107 { sid, fizz: 'buzz' },108 test.remoteTrackPublicationV2s[0].update.args[0][0]);109 });110 });111 context('which includes a trackState matching an existing RemoteTrackPublicationV2', () => {112 it('calls update with the trackState on the existing RemoteTrackPublicationV2', () => {113 const sid = makeSid();114 const test = makeTest({ tracks: [{ sid }] });115 const participantState = test.state(test.revision + 1).setTrack({ sid, fizz: 'buzz' });116 test.participant.update(participantState);117 assert.deepEqual(118 { sid, fizz: 'buzz' },119 test.remoteTrackPublicationV2s[0].update.args[1][0]);120 });121 });122 context('which no longer includes a trackState matching an existing RemoteTrackPublicationV2', () => {123 it('deletes the RemoteTrackPublicationV2 from the RemoteParticipantV2\'s .tracks Map', () => {124 const sid = makeSid();125 const test = makeTest({ tracks: [{ sid }] });126 const participantState = test.state(test.revision + 1);127 test.participant.update(participantState);128 assert(!test.participant.tracks.has(sid));129 });130 it('emits the "trackRemoved" event with the RemoteTrackPublicationV2', () => {131 const sid = makeSid();132 const test = makeTest({ tracks: [{ sid }] });133 const participantState = test.state(test.revision + 1);134 let track;135 test.participant.once('trackRemoved', _track => { track = _track; });136 test.participant.update(participantState);137 assert.equal(138 test.remoteTrackPublicationV2s[0],139 track);140 });141 });142 context('with .state set to "connected" when the RemoteParticipantV2\'s .state is', () => {143 context('"connected"', () => {144 it('the .state remains "connected"', () => {145 const test = makeTest();146 const participantState = test.state(test.revision + 1).setState('connected');147 test.participant.update(participantState);148 assert.equal(149 'connected',150 test.participant.state);151 });152 it('does not emit the "stateChanged" event', () => {153 const test = makeTest();154 const participantState = test.state(test.revision + 1).setState('connected');155 let stateChanged;156 test.participant.once('stateChanged', () => { stateChanged = true; });157 test.participant.update(participantState);158 assert(!stateChanged);159 });160 });161 context('"disconnected"', () => {162 it('the .state remains "disconnected"', () => {163 const test = makeTest();164 const participantState = test.state(test.revision + 1).setState('connected');165 test.participant.disconnect();166 test.participant.update(participantState);167 assert.equal(168 'disconnected',169 test.participant.state);170 });171 it('does not emit the "stateChanged" event', () => {172 const test = makeTest();173 const participantState = test.state(test.revision + 1).setState('connected');174 test.participant.disconnect();175 let stateChanged;176 test.participant.once('stateChanged', () => { stateChanged = true; });177 test.participant.update(participantState);178 assert(!stateChanged);179 });180 });181 });182 context('with .state set to "disconnected" when the RemoteParticipantV2\'s .state is', () => {183 context('"connected"', () => {184 it('sets the .state to "disconnected"', () => {185 const test = makeTest();186 const participantState = test.state(test.revision + 1).setState('disconnected');187 test.participant.update(participantState);188 assert.equal(189 'disconnected',190 test.participant.state);191 });192 it('emits the "stateChanged" event with the new state "disconnected"', () => {193 const test = makeTest();194 const participantState = test.state(test.revision + 1).setState('disconnected');195 let newState;196 test.participant.once('stateChanged', state => { newState = state; });197 test.participant.update(participantState);198 assert.equal(199 'disconnected',200 newState);201 });202 });203 context('"disconnected"', () => {204 it('the .state remains "disconnected"', () => {205 const test = makeTest();206 const participantState = test.state(test.revision + 1).setState('disconnected');207 test.participant.disconnect();208 test.participant.update(participantState);209 assert.equal(210 'disconnected',211 test.participant.state);212 });213 it('does not emit the "stateChanged" event', () => {214 const test = makeTest();215 const participantState = test.state(test.revision + 1).setState('disconnected');216 test.participant.disconnect();217 let stateChanged;218 test.participant.once('stateChanged', () => { stateChanged = true; });219 test.participant.update(participantState);220 assert(!stateChanged);221 });222 });223 });224 context('which changes the .identity', () => {225 it('the .identity remains unchanged', () => {226 const test = makeTest();227 const participantState = test.state(test.revision + 1).setIdentity(makeIdentity());228 test.participant.update(participantState);229 assert.equal(230 test.identity,231 test.participant.identity);232 });233 });234 context('which changes the .sid', () => {235 it('the .identity remains unchanged', () => {236 const test = makeTest();237 const participantState = test.state(test.revision + 1).setSid(makeSid());238 test.participant.update(participantState);239 assert.equal(240 test.sid,241 test.participant.sid);242 });243 });244 });245 context('the same revision', () => {246 it('returns the RemoteParticipantV2', () => {247 const test = makeTest();248 const participantState = test.state(test.revision);249 assert.equal(250 test.participant,251 test.participant.update(participantState));252 });253 it('does not update the .revision', () => {254 const test = makeTest();255 const participantState = test.state(test.revision);256 test.participant.update(participantState);257 assert.equal(258 test.revision,259 test.participant.revision);260 });261 context('which includes a new trackState not matching an existing RemoteTrackPublicationV2', () => {262 it('does not construct a new RemoteTrackPublicationV2 from the trackState', () => {263 const test = makeTest();264 const participantState = test.state(test.revision).setTrack({ sid: makeSid() });265 test.participant.update(participantState);266 assert.equal(0, test.remoteTrackPublicationV2s.length);267 });268 it('does not call getTrackTransceiver with a newly-constructed RemoteTrackPublicationV2\'s ID', () => {269 const test = makeTest();270 const participantState = test.state(test.revision).setTrack({ sid: makeSid() });271 test.participant.update(participantState);272 assert(!test.getTrackTransceiver.calledOnce);273 });274 });275 context('which includes a trackState matching an existing RemoteTrackPublicationV2', () => {276 it('does not call update with the trackState on the existing RemoteTrackPublicationV2', () => {277 const sid = makeSid();278 const test = makeTest({ tracks: [{ sid }] });279 const participantState = test.state(test.revision).setTrack({ sid });280 test.participant.update(participantState);281 assert(!test.remoteTrackPublicationV2s[0].update.calledTwice);282 });283 });284 context('which no longer includes a trackState matching an existing RemoteTrackPublicationV2', () => {285 it('does not delete the RemoteTrackPublicationV2 from the RemoteParticipantV2\'s .tracks Map', () => {286 const sid = makeSid();287 const test = makeTest({ tracks: [{ sid }] });288 const participantState = test.state(test.revision);289 test.participant.update(participantState);290 assert.equal(291 test.remoteTrackPublicationV2s[0],292 test.participant.tracks.get(sid));293 });294 it('does not emit the "trackRemoved" event with the RemoteTrackPublicationV2', () => {295 const sid = makeSid();296 const test = makeTest({ tracks: [{ sid }] });297 const participantState = test.state(test.revision);298 let trackRemoved;299 test.participant.once('trackRemoved', () => { trackRemoved = false; });300 test.participant.update(participantState);301 assert(!trackRemoved);302 });303 });304 context('with .state set to "connected" when the RemoteParticipantV2\'s .state is', () => {305 context('"connected"', () => {306 it('the .state remains "connected"', () => {307 const test = makeTest();308 const participantState = test.state(test.revision).setState('connected');309 test.participant.update(participantState);310 assert.equal(311 'connected',312 test.participant.state);313 });314 it('does not emit the "stateChanged" event', () => {315 const test = makeTest();316 const participantState = test.state(test.revision).setState('connected');317 let stateChanged;318 test.participant.once('stateChanged', () => { stateChanged = true; });319 test.participant.update(participantState);320 assert(!stateChanged);321 });322 });323 context('"disconnected"', () => {324 it('the .state remains "disconnected"', () => {325 const test = makeTest();326 const participantState = test.state(test.revision).setState('connected');327 test.participant.disconnect();328 test.participant.update(participantState);329 assert.equal(330 'disconnected',331 test.participant.state);332 });333 it('does not emit the "stateChanged" event', () => {334 const test = makeTest();335 const participantState = test.state(test.revision).setState('connected');336 test.participant.disconnect();337 let stateChanged;338 test.participant.once('stateChanged', () => { stateChanged = true; });339 test.participant.update(participantState);340 assert(!stateChanged);341 });342 });343 });344 context('with .state set to "disconnected" when the RemoteParticipantV2\'s .state is', () => {345 context('"connected"', () => {346 it('the .state remains "connected"', () => {347 const test = makeTest();348 const participantState = test.state(test.revision).setState('disconnected');349 test.participant.update(participantState);350 assert.equal(351 'connected',352 test.participant.state);353 });354 it('does not emit the "stateChanged" event', () => {355 const test = makeTest();356 const participantState = test.state(test.revision).setState('disconnected');357 let stateChanged;358 test.participant.once('stateChanged', () => { stateChanged = true; });359 test.participant.update(participantState);360 assert(!stateChanged);361 });362 });363 context('"disconnected"', () => {364 it('the .state remains "disconnected"', () => {365 const test = makeTest();366 const participantState = test.state(test.revision).setState('disconnected');367 test.participant.disconnect();368 test.participant.update(participantState);369 assert.equal(370 'disconnected',371 test.participant.state);372 });373 it('does not emit the "stateChanged" event', () => {374 const test = makeTest();375 const participantState = test.state(test.revision).setState('disconnected');376 test.participant.disconnect();377 let stateChanged;378 test.participant.once('stateChanged', () => { stateChanged = true; });379 test.participant.update(participantState);380 assert(!stateChanged);381 });382 });383 });384 context('which changes the .identity', () => {385 it('the .identity remains unchanged', () => {386 const test = makeTest();387 const participantState = test.state(test.revision).setIdentity(makeIdentity());388 test.participant.update(participantState);389 assert.equal(390 test.identity,391 test.participant.identity);392 });393 });394 context('which changes the .sid', () => {395 it('the .identity remains unchanged', () => {396 const test = makeTest();397 const participantState = test.state(test.revision).setSid(makeSid());398 test.participant.update(participantState);399 assert.equal(400 test.sid,401 test.participant.sid);402 });403 });404 });405 context('an older revision', () => {406 it('returns the RemoteParticipantV2', () => {407 const test = makeTest();408 const participantState = test.state(test.revision - 1);409 test.participant.update(participantState);410 assert.equal(411 test.revision,412 test.participant.revision);413 });414 it('does not update the .revision', () => {415 const test = makeTest();416 const participantState = test.state(test.revision - 1);417 test.participant.update(participantState);418 assert.equal(419 test.revision,420 test.participant.revision);421 });422 context('which includes a new trackState not matching an existing RemoteTrackPublicationV2', () => {423 it('does not construct a new RemoteTrackPublicationV2 from the trackState', () => {424 const test = makeTest();425 const participantState = test.state(test.revision - 1).setTrack({ sid: makeSid() });426 test.participant.update(participantState);427 assert.equal(0, test.remoteTrackPublicationV2s.length);428 });429 it('does not call getTrackTransceiver with a newly-constructed RemoteTrackPublicationV2\'s ID', () => {430 const test = makeTest();431 const participantState = test.state(test.revision - 1).setTrack({ sid: makeSid() });432 test.participant.update(participantState);433 assert(!test.getTrackTransceiver.calledOnce);434 });435 });436 context('which includes a trackState matching an existing RemoteTrackPublicationV2', () => {437 it('does not call update with the trackState on the existing RemoteTrackPublicationV2', () => {438 const sid = makeSid();439 const test = makeTest({ tracks: [{ sid }] });440 const participantState = test.state(test.revision - 1).setTrack({ sid });441 test.participant.update(participantState);442 assert(!test.remoteTrackPublicationV2s[0].update.calledTwice);443 });444 });445 context('which no longer includes a trackState matching an existing RemoteTrackPublicationV2', () => {446 it('does not delete the RemoteTrackPublicationV2 from the RemoteParticipantV2\'s .tracks Map', () => {447 const sid = makeSid();448 const test = makeTest({ tracks: [{ sid }] });449 const participantState = test.state(test.revision - 1);450 test.participant.update(participantState);451 assert.equal(452 test.remoteTrackPublicationV2s[0],453 test.participant.tracks.get(sid));454 });455 it('does not emit the "trackRemoved" event with the RemoteTrackPublicationV2', () => {456 const sid = makeSid();457 const test = makeTest({ tracks: [{ sid }] });458 const participantState = test.state(test.revision - 1);459 let trackRemoved;460 test.participant.once('trackRemoved', () => { trackRemoved = false; });461 test.participant.update(participantState);462 assert(!trackRemoved);463 });464 });465 context('with .state set to "connected" when the RemoteParticipantV2\'s .state is', () => {466 context('"connected"', () => {467 it('the .state remains "connected"', () => {468 const test = makeTest();469 const participantState = test.state(test.revision - 1).setState('connected');470 test.participant.update(participantState);471 assert.equal(472 'connected',473 test.participant.state);474 });475 it('does not emit the "stateChanged" event', () => {476 const test = makeTest();477 const participantState = test.state(test.revision - 1).setState('connected');478 let stateChanged;479 test.participant.once('stateChanged', () => { stateChanged = true; });480 test.participant.update(participantState);481 assert(!stateChanged);482 });483 });484 context('"disconnected"', () => {485 it('the .state remains "disconnected"', () => {486 const test = makeTest();487 const participantState = test.state(test.revision - 1).setState('connected');488 test.participant.disconnect();489 test.participant.update(participantState);490 assert.equal(491 'disconnected',492 test.participant.state);493 });494 it('does not emit the "stateChanged" event', () => {495 const test = makeTest();496 const participantState = test.state(test.revision - 1).setState('connected');497 test.participant.disconnect();498 let stateChanged;499 test.participant.once('stateChanged', () => { stateChanged = true; });500 test.participant.update(participantState);501 assert(!stateChanged);502 });503 });504 });505 context('with .state set to "disconnected" when the RemoteParticipantV2\'s .state is', () => {506 context('"connected"', () => {507 it('the .state remains "connected"', () => {508 const test = makeTest();509 const participantState = test.state(test.revision - 1).setState('disconnected');510 test.participant.update(participantState);511 assert.equal(512 'connected',513 test.participant.state);514 });515 it('does not emit the "stateChanged" event', () => {516 const test = makeTest();517 const participantState = test.state(test.revision - 1).setState('disconnected');518 let stateChanged;519 test.participant.once('stateChanged', () => { stateChanged = true; });520 test.participant.update(participantState);521 assert(!stateChanged);522 });523 });524 context('"disconnected"', () => {525 it('the .state remains "disconnected"', () => {526 const test = makeTest();527 const participantState = test.state(test.revision - 1).setState('disconnected');528 test.participant.disconnect();529 test.participant.update(participantState);530 assert.equal(531 'disconnected',532 test.participant.state);533 });534 it('does not emit the "stateChanged" event', () => {535 const test = makeTest();536 const participantState = test.state(test.revision - 1).setState('disconnected');537 test.participant.disconnect();538 let stateChanged;539 test.participant.once('stateChanged', () => { stateChanged = true; });540 test.participant.update(participantState);541 assert(!stateChanged);542 });543 });544 });545 context('which changes the .identity', () => {546 it('the .identity remains unchanged', () => {547 const test = makeTest();548 const participantState = test.state(test.revision - 1).setIdentity(makeIdentity());549 test.participant.update(participantState);550 assert.equal(551 test.identity,552 test.participant.identity);553 });554 });555 context('which changes the .sid', () => {556 it('the .identity remains unchanged', () => {557 const test = makeTest();558 const participantState = test.state(test.revision - 1).setSid(makeSid());559 test.participant.update(participantState);560 assert.equal(561 test.sid,562 test.participant.sid);563 });564 });565 });566 });567 // ParticipantSignaling568 // --------------------569 describe('#addTrack', () => {570 it('returns the RemoteParticipantV2', () => {571 const RemoteTrackPublicationV2 = makeRemoteTrackPublicationV2Constructor();572 const test = makeTest();573 const track = new RemoteTrackPublicationV2({ sid: makeSid() });574 assert.equal(575 test.participant,576 test.participant.addTrack(track));577 });578 it('adds the RemoteTrackPublicationV2 to the RemoteParticipantV2\'s .tracks Map', () => {579 const RemoteTrackPublicationV2 = makeRemoteTrackPublicationV2Constructor();580 const test = makeTest();581 const sid = makeSid();582 const track = new RemoteTrackPublicationV2({ sid });583 test.participant.addTrack(track);584 assert.equal(585 track,586 test.participant.tracks.get(sid));587 });588 it('emits the "trackAdded" event with the RemoteTrackPublicationV2', () => {589 const RemoteTrackPublicationV2 = makeRemoteTrackPublicationV2Constructor();590 const test = makeTest();591 const track = new RemoteTrackPublicationV2({ sid: makeSid() });592 let trackAdded;593 test.participant.once('trackAdded', track => { trackAdded = track; });594 test.participant.addTrack(track);595 assert.equal(596 track,597 trackAdded);598 });599 });600 describe('#connect', () => {601 context('when the RemoteParticipantV2\'s .state is "connected"', () => {602 it('returns false', () => {603 const test = makeTest();604 assert.equal(605 false,606 test.participant.connect(makeSid(), makeIdentity()));607 });608 it('the .identity remains the same', () => {609 const test = makeTest();610 test.participant.connect(makeSid(), makeIdentity());611 assert.equal(612 test.identity,613 test.participant.identity);614 });615 it('the .sid remains the same', () => {616 const test = makeTest();617 test.participant.connect(makeSid(), makeIdentity());618 assert.equal(619 test.sid,620 test.participant.sid);621 });622 it('the .state remains "connected"', () => {623 const test = makeTest();624 test.participant.connect(makeSid(), makeIdentity());625 assert.equal(626 'connected',627 test.participant.state);628 });629 it('does not emit the "stateChanged" event', () => {630 const test = makeTest();631 let stateChanged;632 test.participant.once('stateChanged', () => { stateChanged = true; });633 test.participant.connect(makeSid(), makeIdentity());634 assert(!stateChanged);635 });636 });637 context('when the RemoteParticipantV2\'s .state is "disconnected"', () => {638 it('returns false', () => {639 const test = makeTest();640 test.participant.disconnect();641 assert.equal(642 false,643 test.participant.connect(makeSid(), makeIdentity()));644 });645 it('the .identity remains the same', () => {646 const test = makeTest();647 test.participant.disconnect();648 test.participant.connect(makeSid(), makeIdentity());649 assert.equal(650 test.identity,651 test.participant.identity);652 });653 it('the .sid remains the same', () => {654 const test = makeTest();655 test.participant.disconnect();656 test.participant.connect(makeSid(), makeIdentity());657 assert.equal(658 test.sid,659 test.participant.sid);660 });661 it('the .state remains "disconnected"', () => {662 const test = makeTest();663 test.participant.disconnect();664 test.participant.connect(makeSid(), makeIdentity());665 assert.equal(666 'disconnected',667 test.participant.state);668 });669 it('does not emit the "stateChanged" event', () => {670 const test = makeTest();671 test.participant.disconnect();672 let stateChanged;673 test.participant.once('stateChanged', () => { stateChanged = true; });674 test.participant.connect(makeSid(), makeIdentity());675 assert(!stateChanged);676 });677 });678 });679 describe('#disconnect', () => {680 context('when the RemoteParticipantV2\'s .state is "connected"', () => {681 it('returns true', () => {682 const test = makeTest();683 assert.equal(684 true,685 test.participant.disconnect());686 });687 it('sets the .state to "disconnected"', () => {688 const test = makeTest();689 test.participant.disconnect();690 assert.equal(691 'disconnected',692 test.participant.state);693 });694 it('emits the "stateChanged" event with the new state "disconnected"', () => {695 const test = makeTest();696 let newState;697 test.participant.once('stateChanged', state => { newState = state; });698 test.participant.disconnect();699 assert.equal(700 'disconnected',701 newState);702 });703 });704 context('when the RemoteParticipantV2\'s .state is "disconnected"', () => {705 it('returns false', () => {706 const test = makeTest();707 test.participant.disconnect();708 assert.equal(709 false,710 test.participant.disconnect());711 });712 it('the .state remains "disconnected"', () => {713 const test = makeTest();714 test.participant.disconnect();715 test.participant.disconnect();716 assert.equal(717 'disconnected',718 test.participant.state);719 });720 it('does not emit the "stateChanged" event', () => {721 const test = makeTest();722 test.participant.disconnect();723 let stateChanged;724 test.participant.once('stateChanged', () => { stateChanged = true; });725 test.participant.disconnect();726 assert(!stateChanged);727 });728 });729 });730 describe('#removeTrack', () => {731 context('when the RemoteTrackPublicationV2 to remove was previously added', () => {732 it('returns the removed RemoteTrackPublicationV2', () => {733 const test = makeTest({ tracks: [{ sid: makeSid() }] });734 assert.equal(735 test.remoteTrackPublicationV2s[0],736 test.participant.removeTrack(test.remoteTrackPublicationV2s[0]));737 });738 it('deletes the RemoteTrackPublicationV2 from the RemoteParticipantV2\'s .tracks Map', () => {739 const test = makeTest({ tracks: [{ sid: makeSid() }] });740 test.participant.removeTrack(test.remoteTrackPublicationV2s[0]);741 assert(!test.participant.tracks.has(test.remoteTrackPublicationV2s[0].sid));742 });743 it('emits the "trackRemoved" event with the RemoteTrackPublicationV2', () => {744 const test = makeTest({ tracks: [{ sid: makeSid() }] });745 let trackRemoved;746 test.participant.once('trackRemoved', track => { trackRemoved = track; });747 test.participant.removeTrack(test.remoteTrackPublicationV2s[0]);748 assert.equal(749 test.remoteTrackPublicationV2s[0],750 trackRemoved);751 });752 });753 context('when the RemoteTrackPublicationV2 to remove was not previously added', () => {754 it('returns false', () => {755 const RemoteTrackPublicationV2 = makeRemoteTrackPublicationV2Constructor();756 const track = new RemoteTrackPublicationV2({ sid: makeSid() });757 const test = makeTest();758 assert.equal(759 null,760 test.participant.removeTrack(track));761 });762 it('does not emit the "trackRemoved" event with the RemoteTrackPublicationV2', () => {763 const RemoteTrackPublicationV2 = makeRemoteTrackPublicationV2Constructor();764 const track = new RemoteTrackPublicationV2({ sid: makeSid() });765 const test = makeTest();766 let trackRemoved;767 test.participant.once('trackRemoved', () => { trackRemoved = true; });768 test.participant.removeTrack(track);769 assert(!trackRemoved);770 });771 });772 });773});774function makeIdentity() {775 return Math.random().toString(36).slice(2);776}777function makeSid() {778 let sid = 'PA';779 for (let i = 0; i < 32; i++) {780 sid += 'abcdef0123456789'.split('')[Math.floor(Math.random() * 16)];781 }782 return sid;783}784function makeRevision() {785 return Math.floor(Math.random() * 101);786}787function makeTest(options) {788 options = options || {};789 options.identity = options.identity || makeIdentity();790 options.revision = options.revision || makeRevision();791 options.sid = options.sid || makeSid();792 options.tracks = options.tracks || [];793 options.remoteTrackPublicationV2s = options.remoteTrackPublicationV2s || [];794 options.getTrackTransceiverDeferred = options.getTrackTransceiverDeferred795 || defer();796 options.getTrackTransceiver = options.getTrackTransceiver797 || sinon.spy(() => options.getTrackTransceiverDeferred.promise);798 options.RemoteTrackPublicationV2 = options.RemoteTrackPublicationV2 || makeRemoteTrackPublicationV2Constructor(options);799 options.participant = options.participant || makeRemoteParticipantV2(options);800 options.state = (revision) => {801 return new RemoteParticipantStateBuilder(options.participant, revision);802 };803 return options;804}805function RemoteParticipantStateBuilder(participant, revision) {806 this.identity = participant.identity;807 this.revision = revision;808 this.state = participant.state;809 this.sid = participant.sid;810 this.tracks = [];811}812RemoteParticipantStateBuilder.prototype.setIdentity = function setIdentity(identity) {813 this.identity = identity;814 return this;815};816RemoteParticipantStateBuilder.prototype.setSid = function setSid(sid) {817 this.sid = sid;818 return this;819};820RemoteParticipantStateBuilder.prototype.setState = function setState(state) {821 this.state = state;822 return this;823};824RemoteParticipantStateBuilder.prototype.setTrack = function setTrack(track) {825 this.tracks.push(track);826 return this;827};828RemoteParticipantStateBuilder.prototype.setTracks = function setTracks(tracks) {829 tracks.forEach(this.setTrack, this);830 return this;831};832function makeRemoteParticipantV2(options) {833 return new RemoteParticipantV2(options, options.getTrackTransceiver, options);834}835function makeRemoteTrackPublicationV2Constructor(testOptions) {836 testOptions = testOptions || {};837 testOptions.remoteTrackPublicationV2s = testOptions.remoteTrackPublicationV2s || [];838 return function RemoteTrackPublicationV2(trackState) {839 this.sid = trackState.sid;840 this.setTrackTransceiver = sinon.spy(() => {});841 this.update = sinon.spy(() => this);842 testOptions.remoteTrackPublicationV2s.push(this);843 };...

Full Screen

Full Screen

drawCardTests.js

Source:drawCardTests.js Github

copy

Full Screen

1const {2 bocha: { assert, refute, sinon },3 createCard,4 Player,5 createMatch,6 FakeConnection2,7 createState,8} = require("./shared.js");9const FatalError = require("../../../../shared/card/FatalError.js");10const GameConfig = require("../../../../shared/match/GameConfig.js");11const Commander = require("../../../../shared/match/commander/Commander.js");12module.exports = {13 "when in draw phase and has 1 card in station draw-row": {14 setUp() {15 this.firstPlayerConnection = FakeConnection2([16 "drawCards",17 "stateChanged",18 ]);19 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);20 const players = [21 Player("P1A", this.firstPlayerConnection),22 Player("P2A", this.secondPlayerConnection),23 ];24 this.match = createMatch({ players });25 this.match.restoreFromState(26 createState({27 playerStateById: {28 P1A: {29 phase: "draw",30 stationCards: [{ place: "draw", card: createCard() }],31 cardsInDeck: [32 createCard({ id: "C2A" }),33 createCard({ id: "C1A" }),34 ],35 },36 },37 })38 );39 this.match.drawCard("P1A");40 },41 "should emit drawCards to first player"() {42 assert.calledOnce(this.firstPlayerConnection.drawCards);43 assert.calledWith(44 this.firstPlayerConnection.drawCards,45 sinon.match({46 moreCardsCanBeDrawn: false,47 })48 );49 },50 "first player should have new card on hand"() {51 this.match.refresh("P1A");52 const {53 cardsOnHand,54 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];55 assert.equals(cardsOnHand.length, 1);56 assert.equals(cardsOnHand[0].id, "C1A");57 },58 "first player should have changed cards in deck count"() {59 this.match.refresh("P1A");60 const {61 playerCardsInDeckCount,62 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];63 assert.equals(playerCardsInDeckCount, 1);64 },65 "second player should have changed opponent cards in deck count"() {66 this.match.refresh("P2A");67 const {68 opponentCardsInDeckCount,69 } = this.secondPlayerConnection.stateChanged.lastCall.args[0];70 assert.equals(opponentCardsInDeckCount, 1);71 },72 "should emit stateChanged to second player"() {73 assert.calledOnce(this.secondPlayerConnection.stateChanged);74 assert.calledWith(75 this.secondPlayerConnection.stateChanged,76 sinon.match({77 opponentCardCount: 1,78 })79 );80 },81 },82 "when in draw phase and has 2 cards in station draw-row": {83 setUp() {84 this.firstPlayerConnection = FakeConnection2([85 "drawCards",86 "stateChanged",87 ]);88 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);89 const players = [90 Player("P1A", this.firstPlayerConnection),91 Player("P2A", this.secondPlayerConnection),92 ];93 this.match = createMatch({ players });94 this.match.restoreFromState(95 createState({96 playerStateById: {97 P1A: {98 phase: "draw",99 stationCards: [100 { place: "draw", card: createCard() },101 { place: "draw", card: createCard() },102 ],103 cardsInDeck: [104 createCard({ id: "C2A" }),105 createCard({ id: "C1A" }),106 ],107 },108 },109 })110 );111 this.match.drawCard("P1A");112 },113 "should emit drawCards to first player"() {114 assert.calledOnce(this.firstPlayerConnection.drawCards);115 assert.calledWith(116 this.firstPlayerConnection.drawCards,117 sinon.match({118 moreCardsCanBeDrawn: true,119 })120 );121 },122 "first player should have new card on hand"() {123 this.match.refresh("P1A");124 const {125 cardsOnHand,126 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];127 assert.equals(cardsOnHand.length, 1);128 assert.equals(cardsOnHand[0].id, "C1A");129 },130 "should emit stateChanged to first player"() {131 assert.calledOnce(this.firstPlayerConnection.stateChanged);132 assert.calledWith(133 this.firstPlayerConnection.stateChanged,134 sinon.match({135 cardsOnHand: [sinon.match({ id: "C1A" })],136 })137 );138 },139 "should emit stateChanged to second player"() {140 assert.calledOnce(this.secondPlayerConnection.stateChanged);141 assert.calledWith(142 this.secondPlayerConnection.stateChanged,143 sinon.match({144 opponentCardCount: 1,145 })146 );147 },148 },149 "when can draw 1 card and draws 2 cards": {150 setUp() {151 this.firstPlayerConnection = FakeConnection2(["drawCards"]);152 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);153 const players = [154 Player("P1A", this.firstPlayerConnection),155 Player("P2A", this.secondPlayerConnection),156 ];157 this.match = createMatch({ players });158 this.match.restoreFromState(159 createState({160 playerStateById: {161 P1A: {162 phase: "draw",163 stationCards: [{ place: "draw", card: createCard() }],164 cardsInDeck: [createCard({ id: "C1A" })],165 },166 },167 })168 );169 this.match.drawCard("P1A");170 this.match.drawCard("P1A");171 },172 "should emit NO cards and that there are no more cards to draw"() {173 const args = this.firstPlayerConnection.drawCards.lastCall.args[0];174 assert.equals(args, { moreCardsCanBeDrawn: false });175 },176 },177 "when can NOT draw more cards in draw phase, but draws one anyway": {178 setUp() {179 this.firstPlayerConnection = FakeConnection2([180 "drawCards",181 "stateChanged",182 ]);183 const players = [184 Player("P1A", this.firstPlayerConnection),185 Player("P2A"),186 ];187 this.match = createMatch({ players });188 this.match.restoreFromState(189 createState({190 playerStateById: {191 P1A: {192 phase: "draw",193 stationCards: [{ place: "draw", card: createCard() }],194 cardsInDeck: [],195 },196 P2A: {197 cardsInDeck: [createCard()],198 },199 },200 })201 );202 this.match.drawCard("P1A");203 },204 "should NOT emit drawCards event"() {205 refute.called(this.firstPlayerConnection.drawCards);206 },207 "should have drawn no more cards to hand"() {208 refute.calledWith(209 this.firstPlayerConnection.stateChanged,210 sinon.match({211 cardsOnHand: sinon.match.array,212 })213 );214 },215 },216 "when discard opponent top 2 cards and has more cards to draw": {217 async setUp() {218 this.firstPlayerConnection = FakeConnection2([219 "drawCards",220 "stateChanged",221 ]);222 this.secondPlayerConnection = FakeConnection2([223 "stateChanged",224 "setOpponentCardCount",225 ]);226 const players = [227 Player("P1A", this.firstPlayerConnection),228 Player("P2A", this.secondPlayerConnection),229 ];230 this.match = createMatch({231 players,232 gameConfig: GameConfig({ millCardCount: 2 }),233 });234 this.match.restoreFromState(235 createState({236 playerStateById: {237 P1A: {238 phase: "draw",239 stationCards: [240 { place: "draw", card: createCard() },241 { place: "draw", card: createCard() },242 ],243 commanders: [Commander.TheMiller],244 },245 P2A: {246 cardsInDeck: [247 createCard({ id: "C2A" }),248 createCard({ id: "C3A" }),249 ],250 },251 },252 })253 );254 this.match.discardOpponentTopTwoCards("P1A");255 },256 "should emit drawCards to first player"() {257 assert.calledOnce(this.firstPlayerConnection.drawCards);258 assert.calledWith(259 this.firstPlayerConnection.drawCards,260 sinon.match({ moreCardsCanBeDrawn: true })261 );262 },263 "first player should NOT have new card on hand"() {264 this.match.refresh("P1A");265 const {266 cardsOnHand,267 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];268 assert.equals(cardsOnHand.length, 0);269 },270 "should NOT emit setOpponentCardCount to second player"() {271 refute.called(this.secondPlayerConnection.setOpponentCardCount);272 },273 "should emit stateChanged to first player"() {274 assert.calledOnce(this.firstPlayerConnection.stateChanged);275 assert.calledWith(276 this.firstPlayerConnection.stateChanged,277 sinon.match({278 opponentDiscardedCards: [279 sinon.match({ id: "C2A" }),280 sinon.match({ id: "C3A" }),281 ],282 events: [sinon.match({ type: "drawCard" })],283 })284 );285 },286 "should emit stateChanged to second player"() {287 assert.calledOnce(this.secondPlayerConnection.stateChanged);288 assert.calledWith(289 this.secondPlayerConnection.stateChanged,290 sinon.match({291 discardedCards: [292 sinon.match({ id: "C2A" }),293 sinon.match({ id: "C3A" }),294 ],295 events: [296 sinon.match({ type: "discardCard" }),297 sinon.match({ type: "discardCard" }),298 ],299 })300 );301 },302 "should have added action log entry"() {303 assert.calledOnce(this.secondPlayerConnection.stateChanged);304 assert.calledWith(305 this.secondPlayerConnection.stateChanged,306 sinon.match({307 actionLogEntries: sinon.match.some(sinon.match({ action: "milled" })),308 })309 );310 },311 },312 "when has draw card requirement with count 1 and draw card": {313 setUp() {314 this.firstPlayerConnection = FakeConnection2([315 "drawCards",316 "stateChanged",317 ]);318 this.secondPlayerConnection = FakeConnection2([319 "stateChanged",320 "setOpponentCardCount",321 ]);322 const players = [323 Player("P1A", this.firstPlayerConnection),324 Player("P2A", this.secondPlayerConnection),325 ];326 this.match = createMatch({ players });327 this.match.restoreFromState(328 createState({329 playerStateById: {330 P1A: {331 phase: "draw",332 requirements: [{ type: "drawCard", count: 1 }],333 cardsInDeck: [createCard({ id: "C1A" })],334 },335 },336 })337 );338 this.match.drawCard("P1A");339 },340 "should emit state changed with requirement removed"() {341 assert.calledOnce(this.firstPlayerConnection.stateChanged);342 assert.calledWith(343 this.firstPlayerConnection.stateChanged,344 sinon.match({345 cardsOnHand: [createCard({ id: "C1A" })],346 events: sinon.match.some(347 sinon.match({ type: "drawCard", byEvent: true })348 ),349 requirements: [],350 })351 );352 },353 "should emit state changed to second player"() {354 assert.calledOnce(this.secondPlayerConnection.stateChanged);355 assert.calledWith(356 this.secondPlayerConnection.stateChanged,357 sinon.match({358 opponentCardCount: 1,359 })360 );361 },362 },363 "when has draw card requirement with count 3 and skip draw card": {364 setUp() {365 this.firstPlayerConnection = FakeConnection2([366 "drawCards",367 "stateChanged",368 ]);369 this.secondPlayerConnection = FakeConnection2([370 "stateChanged",371 "setOpponentCardCount",372 ]);373 const players = [374 Player("P1A", this.firstPlayerConnection),375 Player("P2A", this.secondPlayerConnection),376 ];377 this.match = createMatch({ players });378 this.match.restoreFromState(379 createState({380 playerStateById: {381 P1A: {382 phase: "draw",383 requirements: [384 {385 type: "drawCard",386 cardCommonId: FatalError.CommonId,387 count: 3,388 },389 ],390 cardsInDeck: [createCard({ id: "C1A" })],391 },392 },393 })394 );395 this.match.skipDrawCard("P1A");396 },397 "should emit state changed with requirement removed and with NO cards drawn"() {398 assert.calledOnce(this.firstPlayerConnection.stateChanged);399 assert.calledWith(400 this.firstPlayerConnection.stateChanged,401 sinon.match({402 requirements: [],403 })404 );405 },406 "should NOT emit state changed with cards drawn"() {407 refute.defined(408 this.firstPlayerConnection.stateChanged.lastCall.args[0].cardsOnHand409 );410 },411 },412 "when has draw card requirement with count 1 and mill opponent": {413 setUp() {414 this.firstPlayerConnection = FakeConnection2([415 "drawCards",416 "stateChanged",417 ]);418 this.secondPlayerConnection = FakeConnection2([419 "stateChanged",420 "setOpponentCardCount",421 ]);422 const players = [423 Player("P1A", this.firstPlayerConnection),424 Player("P2A", this.secondPlayerConnection),425 ];426 this.match = createMatch({427 players,428 gameConfig: GameConfig({ millCardCount: 2 }),429 });430 this.match.restoreFromState(431 createState({432 playerStateById: {433 P1A: {434 phase: "draw",435 requirements: [{ type: "drawCard", count: 1 }],436 commanders: [Commander.TheMiller],437 },438 P2A: {439 cardsInDeck: [440 createCard({ id: "C1A" }),441 createCard({ id: "C2A" }),442 ],443 },444 },445 })446 );447 this.match.discardOpponentTopTwoCards("P1A");448 },449 "should emit state changed with requirement removed"() {450 assert.calledOnce(this.firstPlayerConnection.stateChanged);451 assert.calledWith(452 this.firstPlayerConnection.stateChanged,453 sinon.match({454 requirements: [],455 })456 );457 },458 "should NOT register drawCard event"() {459 assert.calledOnce(this.firstPlayerConnection.stateChanged);460 refute.calledWith(461 this.firstPlayerConnection.stateChanged,462 sinon.match({463 events: [],464 })465 );466 },467 "should emit state changed to second player"() {468 assert.calledOnce(this.secondPlayerConnection.stateChanged);469 assert.calledWith(470 this.secondPlayerConnection.stateChanged,471 sinon.match({472 discardedCards: [473 sinon.match({ id: "C1A" }),474 sinon.match({ id: "C2A" }),475 ],476 })477 );478 },479 },480 "when has draw card requirement with count 2 and draw card": {481 setUp() {482 this.firstPlayerConnection = FakeConnection2([483 "drawCards",484 "stateChanged",485 ]);486 this.secondPlayerConnection = FakeConnection2([487 "stateChanged",488 "setOpponentCardCount",489 ]);490 const players = [491 Player("P1A", this.firstPlayerConnection),492 Player("P2A", this.secondPlayerConnection),493 ];494 this.match = createMatch({ players });495 this.match.restoreFromState(496 createState({497 playerStateById: {498 P1A: {499 phase: "draw",500 requirements: [{ type: "drawCard", count: 2 }],501 },502 },503 })504 );505 this.match.drawCard("P1A");506 },507 "should emit state changed with requirement updated"() {508 assert.calledOnce(this.firstPlayerConnection.stateChanged);509 assert.calledWith(510 this.firstPlayerConnection.stateChanged,511 sinon.match({512 requirements: [{ type: "drawCard", count: 1 }],513 })514 );515 },516 },517 "when has COMMON draw card requirement with count 1 and draw card and second player is NOT waiting": {518 setUp() {519 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);520 const players = [521 Player("P1A", this.firstPlayerConnection),522 Player("P2A"),523 ];524 this.match = createMatch({ players });525 this.match.restoreFromState(526 createState({527 playerStateById: {528 P1A: {529 phase: "draw",530 requirements: [{ type: "drawCard", count: 1, common: true }],531 },532 P2A: {533 phase: "wait",534 requirements: [{ type: "drawCard", count: 1, common: true }],535 },536 },537 })538 );539 this.match.drawCard("P1A");540 },541 "should emit state changed with requirement updated to first player"() {542 assert.calledOnce(this.firstPlayerConnection.stateChanged);543 assert.calledWith(544 this.firstPlayerConnection.stateChanged,545 sinon.match({546 requirements: [547 { type: "drawCard", count: 0, common: true, waiting: true },548 ],549 })550 );551 },552 },553 "when has COMMON draw card requirement with count 1 and draw card and second player is waiting": {554 setUp() {555 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);556 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);557 const players = [558 Player("P1A", this.firstPlayerConnection),559 Player("P2A", this.secondPlayerConnection),560 ];561 this.match = createMatch({ players });562 this.match.restoreFromState(563 createState({564 playerStateById: {565 P1A: {566 phase: "draw",567 requirements: [{ type: "drawCard", count: 1, common: true }],568 cardsInDeck: [createCard({ id: "C1A" })],569 },570 P2A: {571 phase: "wait",572 requirements: [573 { type: "drawCard", count: 0, common: true, waiting: true },574 ],575 cardsInDeck: [createCard({ id: "C2A" })],576 },577 },578 })579 );580 this.match.drawCard("P1A");581 },582 "should emit state changed WITHOUT requirement to first player"() {583 assert.calledOnce(this.firstPlayerConnection.stateChanged);584 assert.calledWith(585 this.firstPlayerConnection.stateChanged,586 sinon.match({587 requirements: [],588 })589 );590 },591 "first player should have changed cards in deck count"() {592 this.match.refresh("P1A");593 const {594 playerCardsInDeckCount,595 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];596 assert.equals(playerCardsInDeckCount, 0);597 },598 "second player should have changed opponent cards in deck count"() {599 this.match.refresh("P2A");600 const {601 opponentCardsInDeckCount,602 } = this.secondPlayerConnection.stateChanged.lastCall.args[0];603 assert.equals(opponentCardsInDeckCount, 0);604 },605 "should emit state changed WITHOUT requirement to second player"() {606 assert.calledOnce(this.secondPlayerConnection.stateChanged);607 assert.calledWith(608 this.secondPlayerConnection.stateChanged,609 sinon.match({610 requirements: [],611 })612 );613 },614 },...

Full Screen

Full Screen

discardCardTests.js

Source:discardCardTests.js Github

copy

Full Screen

1const {2 bocha: { sinon, assert, refute },3 createCard,4 createState,5 createMatch,6 Player,7 FakeDeck,8 FakeConnection2,9 catchError,10} = require("./shared.js");11module.exports = {12 "when is action phase and first player discards card": {13 setUp() {14 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);15 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);16 const players = [17 Player("P1A", this.firstPlayerConnection),18 Player("P2A", this.secondPlayerConnection),19 ];20 this.match = createMatch({ players });21 this.match.restoreFromState(22 createState({23 playerStateById: {24 P1A: {25 phase: "action",26 cardsOnHand: [createCard({ id: "C1A" })],27 },28 },29 })30 );31 this.error = catchError(() => this.match.discardCard("P1A", "C1A"));32 },33 "should throw an error"() {34 assert(this.error);35 assert.equals(this.error.message, "Illegal discard");36 },37 "should NOT emit state changed to first player"() {38 refute.called(this.firstPlayerConnection.stateChanged);39 },40 },41 "when is discard phase and first player discards card": {42 setUp() {43 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);44 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);45 const players = [46 Player("P1A", this.firstPlayerConnection),47 Player("P2A", this.secondPlayerConnection),48 ];49 this.match = createMatch({ players });50 this.match.restoreFromState(51 createState({52 playerStateById: {53 P1A: {54 phase: "discard",55 cardsOnHand: [createCard({ id: "C1A" })],56 },57 },58 })59 );60 this.match.discardCard("P1A", "C1A");61 },62 "should emit state changed to first player"() {63 assert.calledOnce(this.firstPlayerConnection.stateChanged);64 assert.calledWith(65 this.firstPlayerConnection.stateChanged,66 sinon.match({67 discardedCards: [sinon.match({ id: "C1A" })],68 })69 );70 },71 "should emit state changed to second player"() {72 assert.calledOnce(this.secondPlayerConnection.stateChanged);73 assert.calledWith(74 this.secondPlayerConnection.stateChanged,75 sinon.match({76 opponentDiscardedCards: [sinon.match({ id: "C1A" })],77 })78 );79 },80 },81 "when discard card in action phase and has discard card requirement of 2 cards": {82 setUp() {83 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);84 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);85 const players = [86 Player("P1A", this.firstPlayerConnection),87 Player("P2A", this.secondPlayerConnection),88 ];89 this.match = createMatch({ players });90 this.match.restoreFromState(91 createState({92 playerStateById: {93 P1A: {94 phase: "action",95 cardsOnHand: [96 createCard({ id: "C1A" }),97 createCard({ id: "C2A" }),98 ],99 requirements: [{ type: "discardCard", count: 2 }],100 },101 P2A: {102 cardsInDeck: [createCard({ id: "C2A" })],103 },104 },105 })106 );107 this.match.discardCard("P1A", "C1A");108 },109 "should emit updated requirement to first player"() {110 assert.calledWith(111 this.firstPlayerConnection.stateChanged,112 sinon.match({113 requirements: [{ type: "discardCard", count: 1 }],114 })115 );116 },117 "first player should NOT have discarded card on hand"() {118 this.match.refresh("P1A");119 const {120 cardsOnHand,121 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];122 assert.equals(cardsOnHand.length, 1);123 assert.equals(cardsOnHand[0].id, "C2A");124 },125 "first player should have requirement to discard 1 card"() {126 this.match.refresh("P1A");127 const {128 requirements,129 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];130 assert.equals(requirements.length, 1);131 assert.equals(requirements[0], { type: "discardCard", count: 1 });132 },133 "should emit state changed to second player WITHOUT bonus card"() {134 assert.calledOnce(this.secondPlayerConnection.stateChanged);135 assert.calledWith(136 this.secondPlayerConnection.stateChanged,137 sinon.match({138 opponentDiscardedCards: [sinon.match({ id: "C1A" })],139 })140 );141 refute.calledWith(142 this.secondPlayerConnection.stateChanged,143 sinon.match({144 cardsOnHand: [sinon.match({ id: "C2A" })],145 })146 );147 },148 },149 "when discard card in action phase and has discard card requirement of 1 card BUT it is after another requirement": {150 setUp() {151 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);152 this.match = createMatch({153 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],154 });155 this.match.restoreFromState(156 createState({157 playerStateById: {158 P1A: {159 phase: "action",160 cardsOnHand: [createCard({ id: "C1A" })],161 requirements: [162 { type: "otherType", count: 3 },163 { type: "discardCard", count: 1 },164 ],165 },166 },167 })168 );169 this.error = catchError(() => this.match.discardCard("P1A", "C1A"));170 },171 "should NOT emit changes to first player"() {172 refute.called(this.firstPlayerConnection.stateChanged);173 },174 "should throw error"() {175 assert(this.error);176 assert.equals(this.error.message, "Illegal discard");177 },178 },179 "when discard card in action phase and has discard card requirement of 1 card": {180 setUp() {181 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);182 this.match = createMatch({183 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],184 });185 this.match.restoreFromState(186 createState({187 playerStateById: {188 P1A: {189 phase: "action",190 cardsOnHand: [createCard({ id: "C1A" })],191 requirements: [192 { type: "discardCard", count: 1 },193 { type: "otherType", count: 3 },194 ],195 },196 },197 })198 );199 this.match.discardCard("P1A", "C1A");200 },201 "should emit requirements list without discard card requirement to first player"() {202 assert.calledWith(203 this.firstPlayerConnection.stateChanged,204 sinon.match({205 requirements: [{ type: "otherType", count: 3 }],206 })207 );208 },209 "first player should NOT have requirement to discard 1 card"() {210 this.match.refresh("P1A");211 const {212 requirements,213 } = this.firstPlayerConnection.stateChanged.lastCall.args[0];214 assert.equals(requirements.length, 1);215 assert.equals(requirements[0], { type: "otherType", count: 3 });216 },217 },218 "when discard last card of requirement but has 2 other requirements": {219 setUp() {220 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);221 this.match = createMatch({222 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],223 });224 this.match.restoreFromState(225 createState({226 playerStateById: {227 P1A: {228 phase: "action",229 cardsOnHand: [createCard({ id: "C1A" })],230 requirements: [231 { type: "discardCard", count: 1 },232 { type: "discardCard" },233 { type: "third" },234 { type: "fourth" },235 ],236 },237 },238 })239 );240 this.match.discardCard("P1A", "C1A");241 },242 "should emit requirements list without first discard card requirement to first player"() {243 assert.calledWith(244 this.firstPlayerConnection.stateChanged,245 sinon.match({246 requirements: [247 { type: "discardCard" },248 { type: "third" },249 { type: "fourth" },250 ],251 })252 );253 },254 },255 "when discard last card of common requirement": {256 setUp() {257 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);258 this.match = createMatch({259 players: [Player("P1A", this.firstPlayerConnection), Player("P2A")],260 });261 this.match.restoreFromState(262 createState({263 playerStateById: {264 P1A: {265 phase: "action",266 cardsOnHand: [createCard({ id: "C1A" })],267 requirements: [{ type: "discardCard", count: 1, common: true }],268 },269 P2A: {270 cardsOnHand: [createCard({ id: "C2A" })],271 requirements: [{ type: "discardCard", count: 1, common: true }],272 },273 },274 })275 );276 this.match.discardCard("P1A", "C1A");277 },278 "should emit requirement as waiting to first player"() {279 assert.calledWith(280 this.firstPlayerConnection.stateChanged,281 sinon.match({282 requirements: [283 { type: "discardCard", count: 0, common: true, waiting: true },284 ],285 })286 );287 },288 },289 "when first player discard last card of common requirement where second player is waiting": {290 setUp() {291 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);292 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);293 const players = [294 Player("P1A", this.firstPlayerConnection),295 Player("P2A", this.secondPlayerConnection),296 ];297 this.match = createMatch({ players });298 this.match.restoreFromState(299 createState({300 playerStateById: {301 P1A: {302 phase: "action",303 cardsOnHand: [createCard({ id: "C1A" })],304 requirements: [{ type: "discardCard", count: 1, common: true }],305 },306 P2A: {307 cardsOnHand: [createCard({ id: "C2A" })],308 requirements: [309 { type: "discardCard", count: 1, common: true, waiting: true },310 ],311 },312 },313 })314 );315 this.match.discardCard("P1A", "C1A");316 },317 "should emit an empty array of requirements to first player"() {318 assert.calledWith(319 this.firstPlayerConnection.stateChanged,320 sinon.match({321 requirements: [],322 })323 );324 },325 "should emit an empty array of requirements to second player"() {326 assert.calledWith(327 this.secondPlayerConnection.stateChanged,328 sinon.match({329 requirements: [],330 })331 );332 },333 },334 "when the opponent has NO cards on hand but a discard card requirement, should remove requirement from both players when someone emits start": {335 setUp() {336 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);337 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);338 const players = [339 Player("P1A", this.firstPlayerConnection),340 Player("P2A", this.secondPlayerConnection),341 ];342 this.match = createMatch({ players });343 this.match.restoreFromState(344 createState({345 playerStateById: {346 P1A: {347 phase: "action",348 requirements: [349 { type: "discardCard", count: 0, common: true, waiting: true },350 ],351 },352 P2A: {353 cardsOnHand: [],354 requirements: [{ type: "discardCard", count: 1, common: true }],355 },356 },357 })358 );359 this.match.start("P2A");360 },361 "should emit an empty array of requirements to first player"() {362 assert.calledWith(363 this.firstPlayerConnection.stateChanged,364 sinon.match({365 requirements: [],366 })367 );368 },369 "should emit an empty array of requirements to second player"() {370 assert.calledWith(371 this.secondPlayerConnection.stateChanged,372 sinon.match({373 requirements: [],374 })375 );376 },377 },...

Full Screen

Full Screen

damageStationCardsTests.js

Source:damageStationCardsTests.js Github

copy

Full Screen

1const {2 bocha: { assert, refute, sinon },3 createCard,4 Player,5 createMatch,6 FakeConnection2,7 catchError,8 createState,9} = require("./shared.js");10module.exports = {11 "when has damageStationCard requirement with count 2 and player has all target station cards": {12 setUp() {13 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);14 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);15 const players = [16 Player("P1A", this.firstPlayerConnection),17 Player("P2A", this.secondPlayerConnection),18 ];19 this.match = createMatch({ players });20 this.match.restoreFromState(21 createState({22 playerStateById: {23 P1A: {24 phase: "action",25 requirements: [{ type: "damageStationCard", count: 2 }],26 },27 P2A: {28 stationCards: [29 { card: createCard({ id: "C1A" }), place: "action" },30 { card: createCard({ id: "C2A" }), place: "action" },31 ],32 },33 },34 })35 );36 this.match.damageStationCards("P1A", { targetIds: ["C1A", "C2A"] });37 },38 "should emit stateChanged with own flipped station card to second player"() {39 assert.calledOnce(this.secondPlayerConnection.stateChanged);40 assert.calledWith(41 this.secondPlayerConnection.stateChanged,42 sinon.match({43 stationCards: [44 sinon.match({45 card: sinon.match({ id: "C1A" }),46 place: "action",47 flipped: true,48 }),49 sinon.match({50 card: sinon.match({ id: "C2A" }),51 place: "action",52 flipped: true,53 }),54 ],55 })56 );57 },58 "should emit stateChanged WITHOUT requirement to first player"() {59 assert.calledOnce(this.firstPlayerConnection.stateChanged);60 assert.calledWith(61 this.firstPlayerConnection.stateChanged,62 sinon.match({63 requirements: [],64 })65 );66 },67 "should emit stateChanged with flipped player station card to first player"() {68 assert.calledOnce(this.firstPlayerConnection.stateChanged);69 assert.calledWith(70 this.firstPlayerConnection.stateChanged,71 sinon.match({72 opponentStationCards: [73 sinon.match({74 card: sinon.match({ id: "C1A" }),75 place: "action",76 flipped: true,77 }),78 sinon.match({79 card: sinon.match({ id: "C2A" }),80 place: "action",81 flipped: true,82 }),83 ],84 })85 );86 },87 },88 "when opponent is MISSING 1 of the 2 target station cards": {89 setUp() {90 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);91 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);92 const players = [93 Player("P1A", this.firstPlayerConnection),94 Player("P2A", this.secondPlayerConnection),95 ];96 this.match = createMatch({ players });97 this.match.restoreFromState(98 createState({99 playerStateById: {100 P1A: {101 phase: "action",102 },103 P2A: {104 stationCards: [105 { card: createCard({ id: "C1A" }), place: "action" },106 ],107 },108 },109 })110 );111 this.error = catchError(() =>112 this.match.damageStationCards("P1A", { targetIds: ["C1A", "C2A"] })113 );114 },115 "should throw error"() {116 assert(this.error);117 assert.equals(this.error.message, "Cannot damage station card");118 },119 "should NOT emit stateChanged to first player"() {120 refute.called(this.firstPlayerConnection.stateChanged);121 },122 "should NOT emit stateChanged to second player"() {123 refute.called(this.secondPlayerConnection.stateChanged);124 },125 },126 "when player does NOT have damageStationCard requirement should throw": {127 setUp() {128 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);129 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);130 const players = [131 Player("P1A", this.firstPlayerConnection),132 Player("P2A", this.secondPlayerConnection),133 ];134 this.match = createMatch({ players });135 this.match.restoreFromState(136 createState({137 playerStateById: {138 P1A: {139 phase: "action",140 stationCards: [141 { card: createCard({ id: "C1A" }), place: "action" },142 ],143 },144 },145 })146 );147 this.error = catchError(() =>148 this.match.damageStationCards("P1A", { targetIds: ["C1A"] })149 );150 },151 "should throw error"() {152 assert(this.error);153 assert.equals(this.error.message, "Cannot damage station card");154 },155 "should NOT emit stateChanged to first player"() {156 refute.called(this.firstPlayerConnection.stateChanged);157 },158 "should NOT emit stateChanged to second player"() {159 refute.called(this.secondPlayerConnection.stateChanged);160 },161 },162 "when player has damageStationCard requirement with count of 1 and has 2 target station cards should throw": {163 setUp() {164 this.firstPlayerConnection = FakeConnection2(["stateChanged"]);165 this.secondPlayerConnection = FakeConnection2(["stateChanged"]);166 const players = [167 Player("P1A", this.firstPlayerConnection),168 Player("P2A", this.secondPlayerConnection),169 ];170 this.match = createMatch({ players });171 this.match.restoreFromState(172 createState({173 playerStateById: {174 P1A: {175 phase: "action",176 stationCards: [177 { card: createCard({ id: "C1A" }), place: "action" },178 { card: createCard({ id: "C2A" }), place: "action" },179 ],180 requirements: [{ type: "damageStationCard", count: 1 }],181 },182 },183 })184 );185 this.error = catchError(() =>186 this.match.damageStationCards("P1A", { targetIds: ["C1A", "C2A"] })187 );188 },189 "should throw error"() {190 assert(this.error);191 assert.equals(this.error.message, "Cannot damage station card");192 },193 "should NOT emit stateChanged to first player"() {194 refute.called(this.firstPlayerConnection.stateChanged);195 },196 "should NOT emit stateChanged to second player"() {197 refute.called(this.secondPlayerConnection.stateChanged);198 },199 },...

Full Screen

Full Screen

browser_required.js

Source:browser_required.js Github

copy

Full Screen

1/* This Source Code Form is subject to the terms of the Mozilla Public2 * License, v. 2.0. If a copy of the MPL was not distributed with this3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */4"use strict";5/* import-globals-from ../../mochitest/role.js */6/* import-globals-from ../../mochitest/states.js */7loadScripts(8 { name: "role.js", dir: MOCHITESTS_DIR },9 { name: "states.js", dir: MOCHITESTS_DIR }10);11/**12 * Test required and aria-required attributes on checkboxes13 * and radio buttons.14 */15addAccessibleTask(16 `17 <form>18 <input type="checkbox" id="checkbox" required>19 <br>20 <input type="radio" id="radio" required>21 <br>22 <input type="checkbox" id="ariaCheckbox" aria-required="true">23 <br>24 <input type="radio" id="ariaRadio" aria-required="true">25 </form>26 `,27 async (browser, accDoc) => {28 // Check initial AXRequired values are correct29 let radio = getNativeInterface(accDoc, "radio");30 is(31 radio.getAttributeValue("AXRequired"),32 1,33 "Correct required val for radio"34 );35 let ariaRadio = getNativeInterface(accDoc, "ariaRadio");36 is(37 ariaRadio.getAttributeValue("AXRequired"),38 1,39 "Correct required val for ariaRadio"40 );41 let checkbox = getNativeInterface(accDoc, "checkbox");42 is(43 checkbox.getAttributeValue("AXRequired"),44 1,45 "Correct required val for checkbox"46 );47 let ariaCheckbox = getNativeInterface(accDoc, "ariaCheckbox");48 is(49 ariaCheckbox.getAttributeValue("AXRequired"),50 1,51 "Correct required val for ariaCheckbox"52 );53 // Change aria-required, verify AXRequired is updated54 let stateChanged = waitForEvent(EVENT_STATE_CHANGE, "ariaCheckbox");55 await SpecialPowers.spawn(browser, [], () => {56 content.document57 .getElementById("ariaCheckbox")58 .setAttribute("aria-required", "false");59 });60 await stateChanged;61 is(62 ariaCheckbox.getAttributeValue("AXRequired"),63 0,64 "Correct required after false set for ariaCheckbox"65 );66 // Remove aria-required, verify AXRequired is updated67 stateChanged = waitForEvent(EVENT_STATE_CHANGE, "ariaCheckbox");68 await SpecialPowers.spawn(browser, [], () => {69 content.document70 .getElementById("ariaCheckbox")71 .removeAttribute("aria-required");72 });73 await stateChanged;74 is(75 ariaCheckbox.getAttributeValue("AXRequired"),76 0,77 "Correct required after removal for ariaCheckbox"78 );79 // Change aria-required, verify AXRequired is updated80 stateChanged = waitForEvent(EVENT_STATE_CHANGE, "ariaRadio");81 await SpecialPowers.spawn(browser, [], () => {82 content.document83 .getElementById("ariaRadio")84 .setAttribute("aria-required", "false");85 });86 await stateChanged;87 is(88 ariaRadio.getAttributeValue("AXRequired"),89 0,90 "Correct required after false set for ariaRadio"91 );92 // Remove aria-required, verify AXRequired is updated93 stateChanged = waitForEvent(EVENT_STATE_CHANGE, "ariaRadio");94 await SpecialPowers.spawn(browser, [], () => {95 content.document96 .getElementById("ariaRadio")97 .removeAttribute("aria-required");98 });99 await stateChanged;100 is(101 ariaRadio.getAttributeValue("AXRequired"),102 0,103 "Correct required after removal for ariaRadio"104 );105 // Remove required, verify AXRequired is updated106 stateChanged = waitForEvent(EVENT_STATE_CHANGE, "checkbox");107 await SpecialPowers.spawn(browser, [], () => {108 content.document.getElementById("checkbox").removeAttribute("required");109 });110 await stateChanged;111 is(112 checkbox.getAttributeValue("AXRequired"),113 0,114 "Correct required after removal for checkbox"115 );116 stateChanged = waitForEvent(EVENT_STATE_CHANGE, "radio");117 await SpecialPowers.spawn(browser, [], () => {118 content.document.getElementById("radio").removeAttribute("required");119 });120 await stateChanged;121 is(122 checkbox.getAttributeValue("AXRequired"),123 0,124 "Correct required after removal for radio"125 );126 }...

Full Screen

Full Screen

button.js

Source:button.js Github

copy

Full Screen

...8 el("js-warning").style.display = "none";9 10 el("button1-p").style.display = "block";11 12 if(stateChanged(0, true)) {13 el("button2-p").style.display = "block";14 } else if(stateChanged(0, false)) {15 el("button2-p").style.display = "none";16 }17 18 if(stateChanged(2, true)) {19 el("button3-p").style.display = "block";20 } else if(stateChanged(2, false)) {21 el("button3-p").style.display = "none";22 }23 24 if(stateChanged(3, true)) {25 el("button1").style.display = "none";26 el("button2").style.display = "none";27 el("button1-color").style.display = "initial";28 el("button2-color").style.display = "initial";29 } else if(stateChanged(3, false)) {30 el("button1").style.display = "initial";31 el("button2").style.display = "initial";32 el("button1-color").style.display = "none";33 el("button2-color").style.display = "none";34 }35 36 if(stateChanged(4, true)) {37 el("button1-p").style.color = "#FF00FF";38 el("button1-p").style.fontWeight = "bold";39 } else if(stateChanged(4, false)) {40 el("button1-p").style.color = "black";41 el("button1-p").style.fontWeight = "normal";42 }43 44 if(stateChanged(5, true)) {45 el("button2-p").style.color = "#3333FF";46 el("button2-p").style.fontWeight = "bold";47 } else if(stateChanged(5, false)) {48 el("button2-p").style.color = "black";49 el("button2-p").style.fontWeight = "normal";50 }51 52 if(stateChanged(6, true)) {53 el("button3-p").style.color = "#44FFFF";54 el("button3-p").style.fontWeight = "bold";55 } else if(stateChanged(6, false)) {56 el("button3-p").style.color = "black";57 el("button3-p").style.fontWeight = "normal";58 }59 60 if(state[4] && state[5] && state[6])61 state[7] = true;62 63 if(stateChanged(7, true)) {64 document.body.style.backgroundColor = "#55FF55";65 } else if(stateChanged(7, false)) {66 document.body.style.backgroundColor = "initial";67 }68 69 if(stateChanged(8, true)) {70 el("button1").style.fontSize = "24px";71 } else if(stateChanged(8, false)) {72 el("button1").style.fontSize = "initial";73 }74 75 if(stateChanged(9, true)) {76 el("score").style.fontSize = "48px";77 el("score").style.fontWeight = "bold";78 el("score").style.color = "#CC00CC";79 el("score").style.textShadow = "3px 3px 0 #0000CC";80 } else if(stateChanged(9, false)) {81 el("score").style.fontSize = "initial";82 el("score").style.fontWeight = "normal";83 el("score").style.color = "black";84 el("score").style.textShadow = "none";85 }86 87 if(state[8] && !state[9])88 state[10] = true;89 90 if(stateChanged(10, true)) {91 document.body.style.transform = "rotate(7deg) translate(50px, 100px)";92 } else if(stateChanged(10, false)) {93 document.body.style.transform = "none";94 }95 96 var score = 0;97 for(var i = 0; i < state.length; i++) {98 if(state[i])99 score += 1;100 }101 el("score").innerHTML = score;102 103 console.log(state);104 prevState = state.slice();105}106function stateChanged(i, newState) {107 if(newState)108 return state[i] && !prevState[i];109 else110 return (!state[i]) && prevState[i];111}112function on(i) {113 state[i] = true;114}115function off(i) {116 state[i] = false;117}118function allOff(i) {119 for(var i = 0; i < state.length; i++)120 state[i] = false;...

Full Screen

Full Screen

browser_link.js

Source:browser_link.js Github

copy

Full Screen

1/* This Source Code Form is subject to the terms of the Mozilla Public2 * License, v. 2.0. If a copy of the MPL was not distributed with this3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */4"use strict";5/* import-globals-from ../../mochitest/role.js */6/* import-globals-from ../../mochitest/states.js */7loadScripts(8 { name: "role.js", dir: MOCHITESTS_DIR },9 { name: "states.js", dir: MOCHITESTS_DIR }10);11ChromeUtils.defineModuleGetter(12 this,13 "PlacesTestUtils",14 "resource://testing-common/PlacesTestUtils.jsm"15);16/**17 * Test visited link properties.18 */19addAccessibleTask(20 `21 <a id="link" href="http://www.example.com/">I am a non-visited link</a><br>22 `,23 async (browser, accDoc) => {24 let link = getNativeInterface(accDoc, "link");25 let stateChanged = waitForEvent(EVENT_STATE_CHANGE, "link");26 is(link.getAttributeValue("AXVisited"), 0, "Link has not been visited");27 await PlacesTestUtils.addVisits(["http://www.example.com/"]);28 await stateChanged;29 is(link.getAttributeValue("AXVisited"), 1, "Link has been visited");30 // Ensure history is cleared before running31 await PlacesUtils.history.clear();32 }33);34/**35 * Test linked vs unlinked anchor tags36 */37addAccessibleTask(38 `39 <a id="link1" href="#">I am a link link</a>40 <a id="link2" onclick="console.log('hi')">I am a link-ish link</a>41 <a id="link3">I am a non-link link</a>42 `,43 async (browser, accDoc) => {44 let link1 = getNativeInterface(accDoc, "link1");45 is(46 link1.getAttributeValue("AXRole"),47 "AXLink",48 "a[href] gets correct link role"49 );50 ok(51 link1.attributeNames.includes("AXVisited"),52 "Link has visited attribute"53 );54 ok(link1.attributeNames.includes("AXURL"), "Link has URL attribute");55 let link2 = getNativeInterface(accDoc, "link2");56 is(57 link2.getAttributeValue("AXRole"),58 "AXLink",59 "a[onclick] gets correct link role"60 );61 ok(62 link2.attributeNames.includes("AXVisited"),63 "Link has visited attribute"64 );65 ok(link2.attributeNames.includes("AXURL"), "Link has URL attribute");66 let link3 = getNativeInterface(accDoc, "link3");67 is(68 link3.getAttributeValue("AXRole"),69 "AXGroup",70 "bare <a> gets correct group role"71 );72 let stateChanged = waitForEvent(EVENT_STATE_CHANGE, "link1");73 await SpecialPowers.spawn(browser, [], () => {74 content.document.getElementById("link1").removeAttribute("href");75 });76 await stateChanged;77 is(78 link1.getAttributeValue("AXRole"),79 "AXGroup",80 "<a> stripped from href gets group role"81 );82 stateChanged = waitForEvent(EVENT_STATE_CHANGE, "link2");83 await SpecialPowers.spawn(browser, [], () => {84 content.document.getElementById("link2").removeAttribute("onclick");85 });86 await stateChanged;87 is(88 link2.getAttributeValue("AXRole"),89 "AXGroup",90 "<a> stripped from onclick gets group role"91 );92 stateChanged = waitForEvent(EVENT_STATE_CHANGE, "link3");93 await SpecialPowers.spawn(browser, [], () => {94 content.document95 .getElementById("link3")96 .setAttribute("href", "http://example.com");97 });98 await stateChanged;99 is(100 link3.getAttributeValue("AXRole"),101 "AXLink",102 "href added to bare a gets link role"103 );104 ok(105 link3.attributeNames.includes("AXVisited"),106 "Link has visited attribute"107 );108 ok(link3.attributeNames.includes("AXURL"), "Link has URL attribute");109 }...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1import { Selector } from 'testcafe';2test('My first test', async t => {3 .typeText('#developer-name', 'John Smith')4 .click('#submit-button')5 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');6});7import { Selector } from 'testcafe';8test('My first test', async t => {9 .typeText('#developer-name', 'John Smith')10 .click('#submit-button')11 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');12});13import { Selector } from 'testcafe';14test('My first test', async t => {15 .typeText('#developer-name', 'John Smith')16 .click('#submit-button')17 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');18});19import { Selector } from 'testcafe';20test('My first test', async t => {21 .typeText('#developer-name', 'John Smith')22 .click('#submit-button')23 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');24});

Full Screen

Using AI Code Generation

copy

Full Screen

1import { Selector } from 'testcafe';2test('My first test', async t => {3 .typeText('#developer-name', 'John Smith')4 .click('#submit-button')5 .wait(10000);6});7export default class Test {8 async stateChanged(state) {9 console.log(state);10 }11}12{ fixture:13 { name: 'Getting Started',14 meta: {} },15 { name: 'My first test',16 meta: {},17 fixture: [Circular] },18 { name: 'chrome',19 os: { name: 'windows', version: '10' },20 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',21 height: 768 },22 errs: [] }23import { Selector } from 'testcafe';24test('My first test', async t => {25 .typeText('#developer-name', 'John Smith')26 .click('#submit-button')27 .wait(10000);28});

Full Screen

Using AI Code Generation

copy

Full Screen

1import { Selector } from 'testcafe';2test('My first test', async t => {3 .typeText('#developer-name', 'John Smith')4 .click('#submit-button')5 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');6});7 ('My first test', async t => {8 .typeText('#developer-name', 'John Smith')9 .click('#submit-button')10 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');11 });12test('My first test', async t => {13 .typeText('#developer-name', 'John Smith')14 .click('#submit-button')15 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');16});17 ('My first test', async t => {18 .typeText('#developer-name', 'John Smith')19 .click('#submit-button')20 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');21 });22test('My first test', async t => {23 .typeText('#developer-name', 'John Smith')24 .click('#submit-button')25 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');26});27 ('My first test', async t => {28 .typeText('#developer-name', 'John Smith')29 .click('#submit-button')30 .expect(Selector('#

Full Screen

Using AI Code Generation

copy

Full Screen

1import { Selector } from 'testcafe';2test('My first test', async t => {3 .typeText('#developer-name', 'John Smith')4 .click('#submit-button')5 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');6});7 ('My second test', async t => {8 .typeText('#developer-name', 'John Smith')9 .click('#submit-button')10 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');11 });12 ('My third test', async t => {13 .typeText('#developer-name', 'John Smith')14 .click('#submit-button')15 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');16 });17 ('My fourth test', async t => {18 .typeText('#developer-name', 'John Smith')19 .click('#submit-button')20 .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');21 });22 ('My fifth test', async t => {23 .typeText('#developer-name', 'John Smith')24 .click('#submit-button')

Full Screen

Using AI Code Generation

copy

Full Screen

1test('My first test', async t => {2 .typeText('#developer-name', 'John Smith')3 .click('#submit-button');4});5const puppeteer = require('puppeteer');6(async () => {7 const browser = await puppeteer.launch();8 const page = await browser.newPage();9 await page.type('#developer-name', 'John Smith');10 await page.click('#submit-button');11 await page.waitForSelector('.result-content');12 await browser.close();13})();14Your name to display (optional):15Your name to display (optional):16 .typeText('#developer-name', 'John Smith')17 .click('#submit-button', { visibilityCheck: true });18Your name to display (optional):19Your name to display (optional):20 .typeText('#developer-name', 'John Smith')21 .click('#submit-button', { visibilityCheck: true });22Your name to display (optional):23Your name to display (optional):

Full Screen

Using AI Code Generation

copy

Full Screen

1import { Selector } from 'testcafe';2test('My first test', async t => {3 .typeText('#developer-name', 'John Smith')4 .click('#submit-button')5 .wait(10000);6});7test('My second test', async t => {8 .typeText('#developer-name', 'John Smith')9 .click('#submit-button')10 .wait(10000);11});12test('My third test', async t => {13 .typeText('#developer-name', 'John Smith')14 .click('#submit-button')15 .wait(10000);16});17test('My fourth test', async t => {18 .typeText('#developer-name', 'John Smith')19 .click('#submit-button')20 .wait(10000);21});22test('My fifth test', async t => {23 .typeText('#developer-name', 'John Smith')24 .click('#submit-button')25 .wait(10000);26});27test('My sixth test', async t => {28 .typeText('#developer-name', 'John Smith')29 .click('#submit-button')30 .wait(10000);31});32test('My seventh test', async t => {33 .typeText('#developer-name', 'John Smith')34 .click('#submit-button')35 .wait(10000);36});37test('My eighth test', async t => {38 .typeText('#developer-name', 'John Smith')39 .click('#submit-button')40 .wait(10000);41});42test('My ninth test', async t => {43 .typeText('#developer-name', 'John Smith')44 .click('#submit-button')45 .wait(10000);46});

Full Screen

Using AI Code Generation

copy

Full Screen

1import { Selector, t } from 'testcafe';2test('My first test', async t => {3 console.log("Test Started");4 .typeText('#developer-name', 'John Smith')5 .click('#macos')6 .click('#submit-button');7 console.log("Test Ended");8});9import { Selector, t } from 'testcafe';10test('My first test', async t => {11 console.log("Test Started");12 .typeText('#developer-name', 'John Smith')13 .click('#macos')14 .click('#submit-button');15 console.log("Test Ended");16});

Full Screen

Using AI Code Generation

copy

Full Screen

1import { Selector } from 'testcafe';2test('My first test', async t => {3 const developerNameInput = Selector('#developer-name');4 const populateButton = Selector('#populate');5 .click(populateButton)6 .expect(developerNameInput.value).eql('Peter Parker')7 .typeText(developerNameInput, ' ')8 .expect(developerNameInput.value).eql('Peter Parker ')9 .typeText(developerNameInput, 'Spiderman')10 .expect(developerNameInput.value).eql('Peter Parker Spiderman')11 .click('#submit-button')12 .wait(5000);13});14import { Selector } from 'testcafe';15test('My first test', async t => {16 const developerNameInput = Selector('#developer-name');17 const populateButton = Selector('#populate');18 const submitButton = Selector('#submit-button');19 const thankYouMessage = Selector('#article-header').withText('Thank you, Peter Parker Spiderman!');20 const nameInput = Selector('#article-header').withText('Name: Peter Parker Spiderman');21 const osInput = Selector('#article-header').withText('Operating system: Windows');22 const featureInput = Selector('#article-header').withText('Feature: Support for testing on remote devices');23 .click(populateButton)24 .expect(developerNameInput.value).eql('Peter Parker')25 .typeText(developerNameInput, ' ')26 .expect(developerNameInput.value).eql('Peter Parker ')27 .typeText(developerNameInput, 'Spiderman')

Full Screen

Using AI Code Generation

copy

Full Screen

1test('Test', async t => {2 .typeText('#lst-ib', 'Hello')3 .click('#tsf > div.tsf-p > div.jsb > center > input[type="submit"]:nth-child(1)');4});5 .stateChanged(async (t, state) => {6 console.log(state);7 })8 ('Test', async t => {9 .typeText('#lst-ib', 'Hello')10 .click('#tsf > div.tsf-p > div.jsb > center > input[type="submit"]:nth-child(1)');11 });12import { RequestLogger } from 'testcafe';13 .requestHooks(logger)14 .stateChanged(async (t, state) => {15 const request = logger.requests[0];16 data: {17 }18 });19 })20 ('Test', async t => {21 .typeText('#lst-ib', 'Hello')22 .click('#tsf > div.tsf-p > div.jsb > center > input[type="submit"]:nth-child(1)');23 });24import { RequestLogger } from 'testcafe';

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Testcafe automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful