Files
Battle-for-Tismo/tests/net_test.js
T

226 lines
7.2 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { setupDom, teardownDom, FakeWebSocket } from "./framework/dom.js";
import { Network } from "../client/js/net.js";
export class NetTest extends TestCase {
async connected(url = "ws://localhost/ws") {
const env = await setupDom();
FakeWebSocket.reset();
const network = new Network();
const promise = network.connect(url);
const ws = FakeWebSocket.last;
ws.simulateOpen();
await promise;
return { env, network, ws };
}
async test_default_server_url_uses_the_page_origin() {
const env = await setupDom();
try {
this.assertEqual(new Network().defaultServerUrl(), "ws://localhost/ws");
} finally {
teardownDom(env);
}
}
async test_normalize_url_accepts_hosts_and_urls() {
const env = await setupDom();
try {
const network = new Network();
this.assertEqual(network.normalizeUrl("example.com"), "ws://example.com:27015/ws");
this.assertEqual(network.normalizeUrl("example.com", 1234), "ws://example.com:1234/ws");
this.assertEqual(network.normalizeUrl("http://example.com"), "ws://example.com/ws");
this.assertEqual(network.normalizeUrl("https://example.com/ws"), "wss://example.com/ws");
this.assertEqual(network.normalizeUrl("ws://example.com/socket"), "ws://example.com/socket");
} finally {
teardownDom(env);
}
}
async test_request_game_list_sends_and_receives() {
const { env, network, ws } = await this.connected();
try {
let games = null;
network.on("game_list_received", (value) => {
games = value;
});
const promise = network.requestGameList("ws://localhost/ws");
const socket = FakeWebSocket.last;
socket.simulateOpen();
await promise;
this.assertEqual(socket.sent[0], { t: "request_games" });
socket.simulateMessage({ t: "game_list", games: [{ name: "Game" }] });
this.assertEqual(games, [{ name: "Game" }]);
} finally {
teardownDom(env);
}
}
async test_login_success_emits_session_started() {
const env = await setupDom();
try {
FakeWebSocket.reset();
const network = new Network();
let started = null;
network.on("session_started", (message) => {
started = message;
});
const promise = network.createGame("Alice", "pw");
const ws = FakeWebSocket.last;
ws.simulateOpen();
await promise;
this.assertEqual(ws.lastSent(), { t: "login", name: "Alice", password: "pw" });
this.assertFalse(network.isClientConnected());
ws.simulateMessage({ t: "assigned", playerId: 7, admin: true, name: "Alice" });
this.assertEqual(started.playerId, 7);
this.assertEqual(network.localPlayerId, 7);
this.assertTrue(network.isAdmin);
this.assertTrue(network.isClientConnected());
} finally {
teardownDom(env);
}
}
async test_login_rejection_emits_session_failed() {
const { env, network, ws } = await this.connected();
try {
let failed = null;
network.on("session_failed", (message) => {
failed = message;
});
ws.simulateMessage({ t: "login_rejected", reason: "Wrong password for Alice." });
this.assertEqual(failed, "Wrong password for Alice.");
} finally {
teardownDom(env);
}
}
async test_players_and_game_state_events() {
const { env, network, ws } = await this.connected();
try {
let players = null;
let state = null;
network.on("players_updated", (value) => {
players = value;
});
network.on("game_state_received", (value) => {
state = value;
});
ws.simulateMessage({ t: "players", players: { 1: { id: 1, name: "A", admin: true } } });
this.assertEqual(players["1"].name, "A");
this.assertTrue(network.players["1"].admin);
ws.simulateMessage({ t: "game_state", state: { seed: 5, viewer: 0 } });
this.assertEqual(state.seed, 5);
} finally {
teardownDom(env);
}
}
async test_game_state_deltas_merge_into_the_last_full_state() {
const { env, network, ws } = await this.connected();
try {
let state = null;
network.on("game_state_received", (value) => {
state = value;
});
ws.simulateMessage({
t: "game_state",
state: { seed: 5, viewer: 0, territory: [[0, 0, 1]], explored: [[0, 0]], units: [] },
});
this.assertEqual(state.territory.length, 1, "the first state is used whole");
// A delta updates only what it carries and keeps the rest.
ws.simulateMessage({
t: "game_state",
state: { delta: true, units: [{ id: 1 }], exploredAdded: [[1, 0]] },
});
this.assertEqual(state.territory.length, 1, "unchanged territory is kept");
this.assertSize(state.units, 1, "the changed field is updated");
this.assertSize(state.explored, 2, "newly explored tiles are appended");
this.assertEqual(state.explored[1], [1, 0]);
this.assertNull(state.exploredAdded, "the temporary tail is dropped");
// A full state replaces the base.
ws.simulateMessage({
t: "game_state",
state: { seed: 6, viewer: 0, territory: [], explored: [], units: [] },
});
this.assertEqual(state.seed, 6, "a full state replaces the base");
} finally {
teardownDom(env);
}
}
async test_disconnected_without_failure_reports_it() {
const { env, network, ws } = await this.connected();
try {
let disconnected = false;
network.on("server_disconnected", () => {
disconnected = true;
});
ws.simulateClose();
this.assertTrue(disconnected);
} finally {
teardownDom(env);
}
}
async test_send_order_is_ignored_while_disconnected() {
const env = await setupDom();
try {
FakeWebSocket.reset();
const network = new Network();
network.sendOrder({ type: "move" });
this.assertEmpty(FakeWebSocket.instances, "no socket was opened");
network.close();
} finally {
teardownDom(env);
}
}
async test_join_game_sends_login() {
const env = await setupDom();
try {
FakeWebSocket.reset();
const network = new Network();
const promise = network.joinGame("ws://example.com/ws", "Bob", "pw");
const ws = FakeWebSocket.last;
this.assertEqual(ws.url, "ws://example.com/ws");
ws.simulateOpen();
await promise;
this.assertEqual(ws.lastSent(), { t: "login", name: "Bob", password: "pw" });
} finally {
teardownDom(env);
}
}
async test_unknown_messages_are_ignored() {
const { env, network, ws } = await this.connected();
try {
ws.simulateMessage({ t: "something-unknown" });
this.assertEqual(network.localPlayerId, 0);
} finally {
teardownDom(env);
}
}
async test_connection_error_rejects_the_connect_promise() {
const env = await setupDom();
try {
FakeWebSocket.reset();
const network = new Network();
const promise = network.connect("ws://localhost/ws");
FakeWebSocket.last.simulateError();
let failed = false;
try {
await promise;
} catch {
failed = true;
}
this.assertTrue(failed, "the connection promise rejected");
} finally {
teardownDom(env);
}
}
}