1
0
Fork 0

Refactoring of TestGame for testing UI

This commit is contained in:
Michaël Lemaire 2017-02-21 23:38:31 +01:00
parent aa3af26790
commit ed0908bfa8
20 changed files with 179 additions and 126 deletions

13
TODO
View file

@ -2,7 +2,7 @@
* Highlight ships that will be included as target of current action
* Do not focus on ship while targetting for area effects (dissociate hover and target)
* Active effects are not enough visible in ship list (maybe better in arena ?)
* All things displayed in battle should be updated from BattleLog, not from current state
* All things displayed in battle should be updated from LogProcess forwarding, not from current game state
* Drones: add tooltip
* Drones: add hull points and take area damage
* More sound effects
@ -11,7 +11,8 @@
* Prevent arena effects information (eg. "shield -36") to overflow out of the arena
* Allow to cancel last moves
* Effect should be random in a range (eg. "damage target 50-75")
* Add an overload/cooling system
* Add critical hit/miss
* Add an overheat/cooling system
* Add auto-move to attack
* Merge identical sticky effects
* Handle effects overflowing ship tooltip when too numerous
@ -32,6 +33,12 @@
* Map: remove jump links that cross the radius of other systems
* Map: improve performance
* Menu: fix background stars aggregating at right side when the game is not focused
* Tutorial
* Campaign save slots
* Missions/quests system
* Main story arc
* Multiplayer
Later, if possible:
* Multiplayer
* Saving to external file
* Saving to cloud

View file

@ -2,15 +2,12 @@
/// <reference path="BaseView.ts" />
module TS.SpaceTac.UI.Specs {
function inview_it(desc: string, func: (view: BaseView) => void) {
var view = new BaseView();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(view);
}, view);
}
describe("BaseView", function () {
let testgame = setupEmptyView();
it("initializes variables", function () {
let view = <BaseView>testgame.ui.state.getCurrentState();
describe("BaseView", () => {
inview_it("initializes variables", function (view) {
expect(view.messages instanceof Messages).toBe(true);
expect(view.inputs instanceof InputManager).toBe(true);

View file

@ -2,17 +2,12 @@
/// <reference path="Boot.ts" />
module TS.SpaceTac.UI.Specs {
function inview_it(desc: string, func: (view: Boot) => void) {
var view = new Boot();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(view);
}, view);
}
describe("Boot", () => {
inview_it("places empty loading background", function (view) {
expect(view.world.children.length).toBe(1);
expect(view.world.children[0] instanceof Phaser.Image).toBe(true);
let testgame = setupSingleView(testgame => [new Boot(), []]);
it("places empty loading background", function () {
expect(testgame.ui.world.children.length).toBe(1);
expect(testgame.ui.world.children[0] instanceof Phaser.Image).toBe(true);
});
});
}

View file

@ -2,15 +2,12 @@
/// <reference path="MainMenu.ts" />
module TS.SpaceTac.UI.Specs {
function inview_it(desc: string, func: (view: MainMenu) => void) {
var view = new MainMenu();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(view);
}, view);
}
describe("MainMenu", () => {
inview_it("adds moving stars, a title and three buttons", function (view) {
let testgame = setupSingleView(testgame => [new MainMenu(), []]);
it("adds moving stars, a title and three buttons", function () {
let view = <MainMenu>testgame.ui.state.getCurrentState();
expect(view.world.children.length).toBe(301);
let group = <Phaser.Group>view.world.children[300];

View file

@ -2,16 +2,11 @@
/// <reference path="Preload.ts" />
module TS.SpaceTac.UI.Specs {
function inview_it(desc: string, func: (view: Preload) => void) {
var view = new Preload();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(view);
}, view);
}
describe("Preload", () => {
inview_it("loads correctly", function (view) {
expect(view.game.state.current).toEqual("test");
let testgame = setupSingleView(testgame => [new Preload(), []]);
it("loads correctly", function () {
expect(testgame.ui.state.current).toEqual("test");
// TODO test asset loading
});
});

View file

@ -2,16 +2,11 @@
/// <reference path="Router.ts" />
module TS.SpaceTac.UI.Specs {
function inview_it(desc: string, func: (view: Router) => void) {
var view = new Router();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(view);
}, view);
}
describe("Router", () => {
inview_it("loads correctly", function (view) {
expect(view.game.state.current).toEqual("test");
let testgame = setupSingleView(testgame => [new Router(), []]);
it("loads correctly", function () {
expect(testgame.ui.state.current).toEqual("test");
// TODO test routing
});
});

View file

@ -2,60 +2,91 @@
/// <reference path="map/UniverseMapView.ts"/>
module TS.SpaceTac.UI.Specs {
// Test game wrapper (use instead of jasmine 'it')
export function ingame_it(desc: string, func: (game: MainUI, state: Phaser.State) => void,
state: Phaser.State = null, ...stateargs: any[]) {
it(desc, (done: () => void) => {
/**
* Class to hold references to test objects (used as singleton in "describe" blocks)
*
* Attributes should only be accessed from inside corresponding "it" blocks (they are initialized by the setup).
*/
export class TestGame {
ui: MainUI;
battleview: BattleView;
mapview: UniverseMapView;
}
/**
* Setup a headless test UI, with a single view started.
*/
export function setupSingleView(buildView: (testgame: TestGame) => [Phaser.State, any[]]) {
let testgame = new TestGame();
beforeEach(function (done) {
spyOn(console, "log").and.stub();
spyOn(console, "warn").and.stub();
var game = new MainUI(true);
testgame.ui = new MainUI(true);
if (game.load) {
spyOn(game.load, 'image').and.stub();
spyOn(game.load, 'audio').and.stub();
if (testgame.ui.load) {
spyOn(testgame.ui.load, 'image').and.stub();
spyOn(testgame.ui.load, 'audio').and.stub();
}
if (!state) {
state = new Phaser.State();
}
let [state, stateargs] = buildView(testgame);
var orig_create = state.create;
state.create = function () {
orig_create.apply(state);
func(game, state);
let orig_create = bound(state, "create");
spyOn(state, "create").and.callFake(() => {
orig_create();
done();
setTimeout(() => {
game.destroy();
}, 1000);
};
});
game.state.add("test", state);
var args = stateargs.slice(0);
args.unshift(true);
args.unshift(true);
args.unshift("test");
game.state.start.apply(game.state, args);
testgame.ui.state.add("test", state);
testgame.ui.state.start("test", true, false, ...stateargs);
});
afterEach(function () {
let ui = testgame.ui;
window.requestAnimationFrame(() => ui.destroy());
testgame.ui = null;
testgame.battleview = null;
testgame.mapview = null;
});
return testgame;
}
/**
* Test setup of an empty BaseView
*/
export function setupEmptyView(): TestGame {
return setupSingleView(testgame => [new BaseView(), []]);
}
/**
* Test setup of a battleview bound to a battle, to be called inside a "describe" block.
*/
export function setupBattleview(): TestGame {
return setupSingleView(testgame => {
testgame.battleview = new BattleView();
let battle = Battle.newQuickRandom();
let player = battle.playing_ship.getPlayer();
return [testgame.battleview, [player, battle]];
});
}
// Test game wrapper, with a battleview initialized on a random battle
export function inbattleview_it(desc: string, func: (battleview: BattleView) => void) {
var battleview = new BattleView();
var battle = Battle.newQuickRandom();
var player = battle.playing_ship.getPlayer();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(battleview);
}, battleview, player, battle);
}
/**
* Test setup of a mapview bound to a universe, to be called inside a "describe" block.
*/
export function setupMapview(): TestGame {
return setupSingleView(testgame => {
testgame.mapview = new UniverseMapView();
// Test game wrapper, with a map initialized on a random universe
export function inmapview_it(desc: string, func: (mapview: UniverseMapView) => void) {
var mapview = new UniverseMapView();
var session = new GameSession();
session.startNewGame();
ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => {
func(mapview);
}, mapview, session.universe, session.player);
let mapview = new UniverseMapView();
let session = new GameSession();
session.startNewGame();
return [testgame.mapview, [session.universe, session.player]];
});
}
}

View file

@ -1,9 +1,11 @@
/// <reference path="../TestGame.ts"/>
module TS.SpaceTac.UI.Specs {
describe("ActionBar", () => {
inbattleview_it("lists available actions for selected ship", (battleview: BattleView) => {
var bar = battleview.action_bar;
describe("ActionBar", function () {
let testgame = setupBattleview();
it("lists available actions for selected ship", function () {
var bar = testgame.battleview.action_bar;
// Ship not owned by current battleview player
var ship = new Ship();
@ -11,7 +13,7 @@ module TS.SpaceTac.UI.Specs {
expect(bar.action_icons.length).toBe(0);
// Ship with no equipment (only endturn action)
battleview.player = ship.getPlayer();
testgame.battleview.player = ship.getPlayer();
bar.setShip(ship);
expect(bar.action_icons.length).toBe(1);
expect(bar.action_icons[0].action.code).toEqual("endturn");
@ -29,7 +31,8 @@ module TS.SpaceTac.UI.Specs {
expect(bar.action_icons[1].action.code).toEqual("fire-gatlinggun");
});
inbattleview_it("mark actions that would become unavailable after use", (battleview: BattleView) => {
it("mark actions that would become unavailable after use", function () {
let battleview = testgame.battleview;
var bar = battleview.action_bar;
var ship = new Ship();
ship.arena_x = 1;
@ -101,8 +104,8 @@ module TS.SpaceTac.UI.Specs {
bar.actionEnded();
});
inbattleview_it("updates power points display", battleview => {
let bar = battleview.action_bar;
it("updates power points display", function () {
let bar = testgame.battleview.action_bar;
function check(available = 0, using = 0, used = 0) {
expect(bar.power.children.length).toBe(available + using + used);
@ -125,7 +128,7 @@ module TS.SpaceTac.UI.Specs {
check();
// owned ship
ship.fleet = battleview.player.fleet;
ship.fleet = testgame.battleview.player.fleet;
bar.setShip(ship);
check(8);

View file

@ -1,8 +1,11 @@
/// <reference path="../TestGame.ts"/>
module TS.SpaceTac.UI.Specs {
describe("ActionTooltip", () => {
inbattleview_it("displays action information", (battleview: BattleView) => {
describe("ActionTooltip", function () {
let testgame = setupBattleview();
it("displays action information", () => {
let battleview = testgame.battleview;
let bar = battleview.action_bar;
let tooltip = bar.tooltip;

View file

@ -1,10 +1,12 @@
/// <reference path="../TestGame.ts"/>
module TS.SpaceTac.UI.Specs {
describe("ArenaShip", () => {
inbattleview_it("adds effects display", (battleview: BattleView) => {
let ship = battleview.battle.playing_ship;
let sprite = battleview.arena.findShipSprite(ship);
describe("ArenaShip", function () {
let testgame = setupBattleview();
it("adds effects display", function () {
let ship = testgame.battleview.battle.playing_ship;
let sprite = testgame.battleview.arena.findShipSprite(ship);
expect(sprite.effects.children.length).toBe(0);

View file

@ -1,8 +1,11 @@
/// <reference path="../TestGame.ts"/>
module TS.SpaceTac.UI.Specs {
describe("BattleView", () => {
inbattleview_it("forwards events in targetting mode", (battleview: BattleView) => {
describe("BattleView", function () {
let testgame = setupBattleview();
it("forwards events in targetting mode", function () {
let battleview = testgame.battleview;
expect(battleview.targetting).toBeNull();
battleview.cursorInSpace(5, 5);

View file

@ -92,8 +92,8 @@ module TS.SpaceTac.UI {
this.battle.endBattle(this.player.fleet);
});
// Inject initial events in battle to populate the LogProcessor
this.battle.injectInitialEvents();
// Start processing the log
this.log_processor.start();
}
// Leaving the view, we unbind the battle

View file

@ -12,7 +12,7 @@ module TS.SpaceTac.UI {
private log: BattleLog;
// Subscription identifier
private subscription: any;
private subscription: any = null;
// Delay before processing next events
private delayed = false;
@ -27,8 +27,14 @@ module TS.SpaceTac.UI {
this.view = view;
this.battle = view.battle;
this.log = view.battle.log;
}
/**
* Start log processing
*/
start() {
this.subscription = this.log.subscribe(event => this.processBattleEvent(event));
this.battle.injectInitialEvents();
}
/**

View file

@ -1,8 +1,11 @@
/// <reference path="../TestGame.ts"/>
module TS.SpaceTac.UI.Specs {
describe("ShipList", () => {
inbattleview_it("handles play position of ships", (battleview: BattleView) => {
describe("ShipList", function () {
let testgame = setupBattleview();
it("handles play position of ships", function () {
let battleview = testgame.battleview;
var list = battleview.ship_list;
expect(battleview.battle.play_order.length).toBe(8);

View file

@ -1,6 +1,8 @@
module TS.SpaceTac.UI.Specs {
describe("Targetting", () => {
it("broadcasts hovering and selection events", () => {
describe("Targetting", function () {
let testgame = setupBattleview();
it("broadcasts hovering and selection events", function () {
var targetting = new Targetting(null);
var hovered: Target[] = [];
@ -21,7 +23,8 @@ module TS.SpaceTac.UI.Specs {
expect(selected).toEqual([Target.newFromLocation(1, 2)]);
});
inbattleview_it("displays action point indicators", (battleview) => {
it("displays action point indicators", function () {
let battleview = testgame.battleview;
let source = new Phaser.Group(battleview.game, battleview.arena);
source.position.set(0, 0);

View file

@ -1,6 +1,9 @@
module TS.SpaceTac.UI.Specs {
describe("WeaponEffect", () => {
inbattleview_it("displays shield hit effect", (battleview) => {
describe("WeaponEffect", function () {
let testgame = setupBattleview();
it("displays shield hit effect", function () {
let battleview = testgame.battleview;
let effect = new WeaponEffect(battleview.arena, new Target(0, 0), new Target(0, 0), new Equipment());
effect.shieldImpactEffect({ x: 10, y: 10 }, { x: 20, y: 15 }, 1000, 3000);
@ -14,7 +17,8 @@ module TS.SpaceTac.UI.Specs {
expect(layer.children[1] instanceof Phaser.Particles.Arcade.Emitter).toBe(true);
});
inbattleview_it("displays gatling gun effect", (battleview) => {
it("displays gatling gun effect", function () {
let battleview = testgame.battleview;
let ship = new Ship();
ship.setArenaPosition(50, 30);
TestTools.setShipHP(ship, 10, 0);

View file

@ -1,8 +1,10 @@
module TS.SpaceTac.UI.Specs {
describe("Animation", () => {
ingame_it("animates rotation", function (game) {
let testgame = setupEmptyView();
it("animates rotation", function () {
let obj = { rotation: -Math.PI * 2.5 };
let tween = game.tweens.create(obj);
let tween = testgame.ui.tweens.create(obj);
let result = Animation.rotationTween(tween, Math.PI * 0.25, 1, Phaser.Easing.Linear.None);
expect(result).toEqual(750);
expect(tween.generateData(4)).toEqual([

View file

@ -1,5 +1,7 @@
module TS.SpaceTac.UI.Specs {
describe("Tools", () => {
describe("Tools", function () {
let testgame = setupEmptyView();
it("normalizes angles", function () {
expect(Tools.normalizeAngle(0)).toEqual(0);
expect(Tools.normalizeAngle(0.1)).toBeCloseTo(0.1, 0.000001);
@ -9,9 +11,9 @@ module TS.SpaceTac.UI.Specs {
expect(Tools.normalizeAngle(-Math.PI - 0.5)).toBeCloseTo(Math.PI - 0.5, 0.000001);
});
ingame_it("handles hover and click on desktops and mobile targets", function (game) {
it("handles hover and click on desktops and mobile targets", function () {
let newButton: () => [Phaser.Button, any] = () => {
var button = new Phaser.Button(game);
var button = new Phaser.Button(testgame.ui);
var funcs = {
enter: () => null,
leave: () => null,

View file

@ -1,7 +1,9 @@
module TS.SpaceTac.UI.Specs {
describe("ValueBar", () => {
ingame_it("computes proportional value", (game: Phaser.Game) => {
var bar = ValueBar.newStandard(game, 0, 0);
describe("ValueBar", function () {
let testgame = setupEmptyView();
it("computes proportional value", function () {
var bar = ValueBar.newStandard(testgame.ui, 0, 0);
expect(bar.getProportionalValue()).toBe(0);

View file

@ -1,6 +1,9 @@
module TS.SpaceTac.UI.Specs {
describe("FleetDisplay", () => {
inmapview_it("orbits the fleet around its current location", mapview => {
describe("FleetDisplay", function () {
let testgame = setupMapview();
it("orbits the fleet around its current location", function () {
let mapview = testgame.mapview;
let fleet = mapview.player_fleet;
fleet.loopOrbit();