Skip to content

Commit

Permalink
fix: server testing qol (#93)
Browse files Browse the repository at this point in the history
* feat(server-testing): support variants in tests

* ci: upgrade sonarcloud
  • Loading branch information
Zielak committed Nov 5, 2023
1 parent 6461b2c commit 4c58b34
Show file tree
Hide file tree
Showing 17 changed files with 361 additions and 210 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ jobs:

orbs:
aws-s3: circleci/[email protected]
sonarcloud: sonarsource/sonarcloud@1.0.1
sonarcloud: sonarsource/sonarcloud@2.0.0

anchors-filters:
- &filters-main-and-development
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/state/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,6 @@ interface Mixin extends IdentityTrait, LabelTrait, ParentTrait {}
export interface State extends Mixin {}

export type StateConstructorOptions<V> = {
variantData: V
variantData?: V
variantDefaults: V
}
37 changes: 37 additions & 0 deletions packages/serverTesting/src/__test__/executeEvent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
type Room,
type State,
type ServerPlayerMessage,
defineRoom,
} from "@cardsgame/server"

import { executeEvent, executeEventSetup } from "../executeEvent.js"
import { makeInteraction } from "../makeInteraction.js"

const roomConstructor = defineRoom("TestingRoom", {})
let room: Room<State>
let event: ServerPlayerMessage

const roomGetter = () => room

beforeEach(() => {
room = new roomConstructor()
room.handleMessage = jest.fn()
room.onCreate()

event = makeInteraction(room.state, { type: "state" }, "tap")
})

describe("calls room.handleMessage", () => {
test("executeEvent", () => {
executeEvent(room, event)

expect(room.handleMessage).toHaveBeenCalledWith(event)
})
test("executeEventInner", () => {
const executeEventInner = executeEventSetup(roomGetter)
executeEventInner(event)

expect(room.handleMessage).toHaveBeenCalledWith(event)
})
})
10 changes: 9 additions & 1 deletion packages/serverTesting/src/__test__/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { defineEntityAction, defineMessageAction } from "@cardsgame/server"
import {
defineEntityAction,
defineMessageAction,
State,
} from "@cardsgame/server"
import { Noop } from "@cardsgame/server/commands"

export const ActionPickCard = defineEntityAction({
Expand All @@ -14,3 +18,7 @@ export const ActionMessage = defineMessageAction({
conditions: () => {},
command: () => new Noop(),
})

export class TestState extends State {
name = "CustomTestState"
}
83 changes: 23 additions & 60 deletions packages/serverTesting/src/__test__/initState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,28 @@ import type { ClassicCard, Hand } from "@cardsgame/server/entities"
import { initState, InitState, initStateSetup } from "../initState.js"

let state: State
const getState = () => state
let initStateInner: InitState<State>

beforeAll(() => {
initStateInner = initStateSetup(State)
initStateInner = initStateSetup(getState)
})

it("creates new State instance", () => {
expect(initStateInner({}) instanceof State).toBeTruthy()
expect(initStateInner() instanceof State).toBeTruthy()
expect(initState({}) instanceof State).toBeTruthy()
expect(initState() instanceof State).toBeTruthy()
beforeEach(() => {
state = new State()
})

describe("children", () => {
it("creates cards", () => {
state = initStateInner({
children: [{ type: "classicCard", name: "D7" }],
})

const firstChild = state.getBottom<ClassicCard>()

expect(firstChild.type).toBe("classicCard")
describe("basics", () => {
it("returns the same state as provided", () => {
expect(initStateInner({})).toBe(state)
expect(initState(getState(), {})).toBe(state)
})

test("type defaults to classicCard", () => {
state = initStateInner({
children: [{ name: "D7" }],
})

const firstChild = state.getBottom<ClassicCard>()

expect(firstChild.type).toBe("classicCard")
})

it("creates children recursively", () => {
state = initStateInner({
children: [
{
type: "hand",
children: [{ name: "D7" }, { name: "C8" }],
},
],
})

const hand = state.getChild<Hand>(0)

expect(hand.type).toBe("hand")
expect(hand.getBottom<ClassicCard>().type).toBe("classicCard")
expect(hand.getBottom<ClassicCard>().name).toBe("D7")
expect(hand.getTop<ClassicCard>().type).toBe("classicCard")
expect(hand.getTop<ClassicCard>().name).toBe("C8")
})

it("prepares selected children", () => {
state = initStateInner({
children: [
{
type: "hand",
children: [{ name: "D7" }, { name: "C8" }],
selected: [1],
},
],
})

const hand = state.getChild<Hand>(0)

expect(hand.isChildSelected(0)).toBe(false)
expect(hand.isChildSelected(1)).toBe(true)
it("requires state preparation object", () => {
// @ts-expect-error test
expect(() => initStateInner()).toThrow()
// @ts-expect-error test
expect(() => initState()).toThrow()
})
})

Expand Down Expand Up @@ -105,14 +59,23 @@ describe("State", () => {
players: [
{ clientID: "namedPlayer", name: "Joe" },
{ clientID: "unnamedPlayer" },
{ name: "Nat" },
{},
],
})

// expect(state.players instanceof ArraySchema).toBe(true)
expect(state.players.length).toBe(2)
expect(state.players.length).toBe(4)
expect(state.players[0].clientID).toBe("namedPlayer")
expect(state.players[0].name).toBe("Joe")

expect(state.players[1].clientID).toBe("unnamedPlayer")
expect(typeof state.players[1].name).toBe("string")

expect(typeof state.players[2].clientID).toBe("string")
expect(state.players[2].name).toBe("Nat")

expect(typeof state.players[3].clientID).toBe("string")
expect(typeof state.players[3].name).toBe("string")
})
})
27 changes: 15 additions & 12 deletions packages/serverTesting/src/__test__/makeInteraction.test.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
import type { ServerPlayerMessage, State } from "@cardsgame/server"
import { type ServerPlayerMessage, State } from "@cardsgame/server"
import { ClassicCard } from "@cardsgame/server/entities"

import { initState } from "../initState.js"
import {
makeInteraction,
MakeInteraction,
makeInteractionSetup,
} from "../makeInteraction.js"
import { PopulateState, populateStateSetup } from "../populateState.js"

let state: State
let makeInteractionInner: MakeInteraction
let events: ServerPlayerMessage[]
const stateGetter = (): State => state

beforeAll(() => {
makeInteractionInner = makeInteractionSetup(() => state)
state = new State()
makeInteractionInner = makeInteractionSetup(stateGetter)

const populateStateInner = populateStateSetup(stateGetter)
populateStateInner([
null,
{
children: [{ type: "classicCard", name: "S6" }],
},
])
})

describe("no state", () => {
it("throws error when no state is available", () => {
state = undefined
expect(() => makeInteraction(state, {})).toThrow("state is undefined")
expect(() => makeInteraction(undefined, {})).toThrow("state is undefined")
})
})

describe("state", () => {
beforeEach(() => {
state = initState({
children: [{ type: "classicCard", name: "S6" }],
})
})

it("properly marks an entity to be interacted", () => {
events = [
makeInteractionInner({ name: "S6" }),
Expand Down Expand Up @@ -57,7 +60,7 @@ describe("state", () => {
describe("interaction", () => {
it("passes interaction type", () => {
expect(
makeInteraction(state, { name: "S6" }, "dragstart").interaction
makeInteraction(state, { name: "S6" }, "dragstart").interaction,
).toBe("dragstart")
})
it("sets default to tap", () => {
Expand Down
30 changes: 17 additions & 13 deletions packages/serverTesting/src/__test__/populateState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,27 @@ import { defaultHandOfCardsSorting, State } from "@cardsgame/server"
import type { ClassicCard, Hand } from "@cardsgame/server/entities"

import { objectsNamed } from "../entityDefinitionHelpers.js"
import { initState } from "../initState.js"
import {
PopulateState,
populateState,
populateStateSetup,
} from "../populateState.js"
import type { StateMockingTuple } from "../types.js"
import type { PopulateStateTuple } from "../types.js"

let state: State
let args: StateMockingTuple[]
let args: PopulateStateTuple[]
let populateStateInner: PopulateState<State>
const stateGetter = (): State => state

beforeAll(() => {
populateStateInner = populateStateSetup(stateGetter)
})
beforeEach(() => {
state = undefined
state = new State()
})

describe("adds child directly to empty state", () => {
beforeEach(() => {
state = new State()
args = [[null, { children: [{ name: "S10" }] }]]
})

Expand All @@ -48,7 +46,7 @@ describe("adds child directly to empty state", () => {

describe("adds children to existing hand", () => {
beforeEach(() => {
state = initState({ children: [{ type: "hand" }] })
populateStateInner([null, { children: [{ type: "hand" }] }])
args = [[{ type: "hand" }, { children: [{ name: "S10" }] }]]
})

Expand Down Expand Up @@ -80,7 +78,7 @@ describe("to existing hand with autoSorting, add and select the FIRST DEFINED ca
// of the array be assigned with
let hand: Hand
beforeEach(() => {
state = initState({ children: [{ type: "hand" }] })
populateStateInner([null, { children: [{ type: "hand" }] }])
hand = state.query<Hand>({ type: "hand" })
hand.autoSort = defaultHandOfCardsSorting

Expand Down Expand Up @@ -113,9 +111,12 @@ describe("to existing hand with autoSorting, add and select the FIRST DEFINED ca

describe("appends some values to existing entities", () => {
beforeEach(() => {
state = initState({
children: [{ type: "hand", children: [{ name: "S10" }] }],
})
populateStateInner([
null,
{
children: [{ type: "hand", children: [{ name: "S10" }] }],
},
])
args = [
[{ type: "hand" }, { name: "namedHand" }],
[{ name: "S10" }, { faceUp: false }],
Expand Down Expand Up @@ -152,9 +153,12 @@ describe("appends some values to existing entities", () => {

describe("throws when adding child to non-parent", () => {
beforeEach(() => {
state = initState({
children: [{ name: "S10" }],
})
populateStateInner([
null,
{
children: [{ name: "S10" }],
},
])
args = [[{ name: "S10" }, { children: [{ name: "SA" }] }]]
})

Expand Down
Loading

0 comments on commit 4c58b34

Please sign in to comment.