1065 lines
44 KiB
JavaScript
1065 lines
44 KiB
JavaScript
import { TestCase } from "./framework/test_case.js";
|
||
import { setupDom, teardownDom } from "./framework/dom.js";
|
||
import { CityModal, NationModal, ConfirmModal, NewsModal } from "../client/js/modals.js";
|
||
import { buildingEffectText, describeNews } from "../client/js/modals/format.js";
|
||
import { BUILDINGS, GOVERNMENTS, TECHNOLOGIES, PROTO_UNITS, technologyCost } from "../shared/data.js";
|
||
import { groupDigits } from "../shared/text_format.js";
|
||
|
||
export class CityModalTest extends TestCase {
|
||
test_utility_buildings_describe_their_mechanic() {
|
||
const barracks = BUILDINGS.find((b) => b.id === "barracks");
|
||
this.assertTrue(
|
||
buildingEffectText(barracks, 2).includes("3 parallel training lines"),
|
||
"the barracks explains its parallel lines"
|
||
);
|
||
const shelters = BUILDINGS.find((b) => b.id === "shelters");
|
||
this.assertTrue(buildingEffectText(shelters, 2).includes("20%"), "the shelters show their protection");
|
||
const market = BUILDINGS.find((b) => b.id === "market");
|
||
this.assertTrue(buildingEffectText(market, 1).includes("production"), "stats keep their effect text");
|
||
}
|
||
showTrain(modal, queue = []) {
|
||
modal.show(
|
||
{ id: 1, name: "Lyon" },
|
||
{
|
||
budget: 1.0e9,
|
||
gdp: 1.0e9,
|
||
trainable: [{ ...PROTO_UNITS[0], serverIndex: 0 }, { ...PROTO_UNITS[2], serverIndex: 2 }],
|
||
buildings: BUILDINGS,
|
||
levels: {},
|
||
queue,
|
||
}
|
||
);
|
||
}
|
||
|
||
async test_train_tab_lists_trainable_units_and_requests_one() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
let requested = null;
|
||
modal.onTrain = (cityId, protoIndex) => {
|
||
requested = [cityId, protoIndex];
|
||
};
|
||
this.showTrain(modal);
|
||
this.assertEqual(env.$("#city-title").text(), "Lyon — City");
|
||
this.assertSize(env.$("#city-train-list button"), 2, "infantry and artillery can be trained");
|
||
this.assertTrue(env.$("#city-train-list button").first().text().includes("Modern infantry"));
|
||
env.$("#city-train-list button").first().click();
|
||
this.assertEqual(requested, [1, 0]);
|
||
modal.close();
|
||
this.assertTrue(env.$("#modal-city").hasClass("hidden"));
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_training_progress_states() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
this.showTrain(modal);
|
||
modal.beginTraining("Modern infantry", 10, 2);
|
||
this.assertFalse(env.$("#city-train-status").hasClass("hidden"));
|
||
modal.setTrainingProgress("Modern infantry", 4, 10);
|
||
this.assertTrue(env.$("#city-train-label").text().includes("6 h left"));
|
||
modal.setTrainingProgress("Market", 1, 5, "Building");
|
||
this.assertTrue(env.$("#city-train-label").text().includes("Building Market"));
|
||
modal.endTraining();
|
||
this.assertEqual(env.$("#city-train-label").text(), "Training complete");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_queue_labels_building_entries_alongside_units() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
const queue = [
|
||
{ kind: "building", protoIndex: 0, elapsedHours: 0, totalHours: 5 },
|
||
{ protoIndex: 0, elapsedHours: 0, totalHours: 10 },
|
||
];
|
||
this.showTrain(modal, queue);
|
||
const rows = env.$("#city-train-queue .queue-row");
|
||
this.assertSize(rows, 2, "a building and a unit never merge");
|
||
this.assertTrue(
|
||
rows.eq(0).text().includes(BUILDINGS[0].name),
|
||
"the building entry is labelled with its name"
|
||
);
|
||
this.assertTrue(rows.eq(1).text().includes("Modern infantry"), "the unit keeps its name");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_queue_merges_only_contiguous_identical_units() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
const cancelled = [];
|
||
modal.onCancel = (cityId, index) => cancelled.push([cityId, index]);
|
||
const queue = [
|
||
{ protoIndex: 0, elapsedHours: 0, totalHours: 10 },
|
||
{ protoIndex: 0, elapsedHours: 0, totalHours: 10 },
|
||
{ protoIndex: 2, elapsedHours: 0, totalHours: 30 },
|
||
{ protoIndex: 0, elapsedHours: 0, totalHours: 10 },
|
||
];
|
||
this.showTrain(modal, queue);
|
||
const rows = env.$("#city-train-queue .queue-row");
|
||
this.assertSize(rows, 3, "only adjacent runs share a row");
|
||
this.assertTrue(rows.eq(0).text().includes("Modern infantry ×2"), "the run is labelled with its size");
|
||
this.assertTrue(rows.eq(0).text().includes("Next in"), "a run shows when its first unit lands");
|
||
this.assertTrue(rows.eq(0).text().includes("all ready in"), "and when the run completes");
|
||
this.assertTrue(rows.eq(1).text().includes("Artillery"), "a different type starts a row");
|
||
this.assertTrue(rows.eq(2).text().includes("Modern infantry"), "a later run of the same type is separate");
|
||
this.assertFalse(rows.eq(2).text().includes("×"), "the lone trailing unit is not a run");
|
||
rows.eq(0).find("button").click();
|
||
this.assertEqual(cancelled, [[1, 1]], "cancelling a run removes its last unit");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_buildings_tab_prices_rows_and_requests_build_and_demolish() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
let built = null;
|
||
let demolished = null;
|
||
modal.onBuild = (cityId, index) => {
|
||
built = [cityId, index];
|
||
};
|
||
modal.onDemolish = (cityId, index) => {
|
||
demolished = [cityId, index];
|
||
};
|
||
modal.show({ id: 3, name: "Lyon" }, { budget: 1.0e15, buildings: BUILDINGS, levels: {} });
|
||
this.assertSize(env.$("#city-buildings-list .row-card"), BUILDINGS.length);
|
||
const first = env.$("#city-buildings-list .row-card").first();
|
||
this.assertTrue(first.find(".name").text().includes("Level 0"));
|
||
this.assertFalse(first.find(".actions button").first().prop("disabled"));
|
||
first.find(".actions button").first().click();
|
||
this.assertEqual(built, [3, 0]);
|
||
|
||
modal.refreshBuildings(1.0e15, { 0: 1 });
|
||
this.assertTrue(first.find(".name").text().includes("Level 1"));
|
||
first.find(".actions button").eq(1).click();
|
||
this.assertEqual(demolished, [3, 0]);
|
||
modal.close();
|
||
this.assertTrue(env.$("#modal-city").hasClass("hidden"));
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_queued_levels_price_the_next_upgrade_higher() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
modal.show({ id: 1, name: "X" }, { budget: 1.0e15, buildings: BUILDINGS, levels: {}, gdp: 1.0e9 });
|
||
const first = env.$("#city-buildings-list .row-card").first();
|
||
const plain = first.find(".cost").text();
|
||
modal.refreshBuildings(1.0e15, {}, 1.0e9, { 0: 1 });
|
||
const queued = first.find(".cost").text();
|
||
this.assertTrue(first.find(".name").text().includes("queued"), "the pending level is shown");
|
||
this.assertNotEqual(queued, plain, "the next order is priced off the queued level");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_upgrade_stays_available_on_an_empty_treasury() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
modal.show({ id: 1, name: "X" }, { budget: 0, buildings: BUILDINGS, levels: {} });
|
||
const upgrade = env.$("#city-buildings-list .row-card").first().find(".actions button").first();
|
||
// The government can always pay, running an overdraft, so cost never
|
||
// disables the button; only an unmet requirement does.
|
||
this.assertFalse(upgrade.prop("disabled"));
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_budget_tab_renders_region_income_and_upkeep() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
const breakdown = {
|
||
income: {
|
||
rate: 0.001,
|
||
base: 900,
|
||
modifier: 0.15,
|
||
total: 1035,
|
||
sources: [
|
||
{ label: "Bank", kind: "building", effect: 0.05, amount: 45, cityId: 1, cityName: "Paris" },
|
||
],
|
||
},
|
||
buildingUpkeep: {
|
||
total: 400,
|
||
sources: [{ label: "Bank", kind: "building", amount: 400 }],
|
||
groups: [
|
||
{
|
||
index: 1,
|
||
label: "Bank",
|
||
amount: 400,
|
||
cities: [{ cityId: 1, cityName: "Paris", level: 2, amount: 400 }],
|
||
},
|
||
],
|
||
},
|
||
unitUpkeep: { total: 0, sources: [], groups: [] },
|
||
net: 635,
|
||
};
|
||
modal.show({ id: 1, name: "Paris" }, { budget: 1.0e15, buildings: BUILDINGS, levels: {} });
|
||
modal.renderBudget(breakdown);
|
||
this.assertTrue(env.$("#city-budget-sub").text().includes("+¤635/h"), "the region net is shown");
|
||
const text = env.$("#city-budget-list").text();
|
||
this.assertTrue(text.includes("+¤1 035/h"), "region tax income is green");
|
||
this.assertTrue(text.includes("Bank in Paris (building) +5.0%"), "a building bonus is listed");
|
||
this.assertTrue(text.includes("−¤400/h"), "the building upkeep is listed");
|
||
this.assertTrue(text.includes("TOTAL"), "a total row is present");
|
||
this.assertTrue(text.includes("+¤635/h"), "the total carries the region net");
|
||
this.assertFalse(text.includes("No units"), "unit upkeep is national, not regional");
|
||
|
||
env.$("#city-budget-list tr.budget-group .budget-name").click();
|
||
this.assertTrue(
|
||
env.$("#city-budget-list").text().includes("Bank in Paris — level 2"),
|
||
"expanding a building type shows its level"
|
||
);
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_tabs_switch_the_visible_page() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
this.showTrain(modal);
|
||
this.assertTrue(env.$("#city-tab-train").hasClass("active"));
|
||
env.$("#modal-city .tab[data-tab=buildings]").click();
|
||
this.assertTrue(env.$("#city-tab-buildings").hasClass("active"));
|
||
this.assertFalse(env.$("#city-tab-train").hasClass("active"));
|
||
env.$("#modal-city .tab[data-tab=budget]").click();
|
||
this.assertTrue(env.$("#city-tab-budget").hasClass("active"));
|
||
env.$("#modal-city .tab[data-tab=train]").click();
|
||
this.assertTrue(env.$("#city-tab-train").hasClass("active"));
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_economy_tab_shows_the_regions_cash_basket() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
modal.show(
|
||
{ id: 1, name: "Lyon" },
|
||
{
|
||
budget: 1.0e9,
|
||
gdp: 1.0e9,
|
||
cash: { FRF: 4000, GBP: 250 },
|
||
cashValue: 4250,
|
||
debt: 250,
|
||
currencies: [
|
||
{ code: "FRF", symbol: "₣", name: "French Franc" },
|
||
{ code: "GBP", symbol: "£", name: "British Pound" },
|
||
],
|
||
}
|
||
);
|
||
env.$("#modal-city .tab[data-tab=economy]").click();
|
||
this.assertTrue(env.$("#city-tab-economy").hasClass("active"));
|
||
const text = env.$("#city-economy-list").text();
|
||
this.assertTrue(text.includes("French Franc"), "the national currency is listed");
|
||
this.assertTrue(text.includes("British Pound"), "a foreign holding is listed");
|
||
this.assertTrue(env.$("#city-economy-sub").text().includes("4 250"), "the total value shows");
|
||
this.assertTrue(env.$("#city-economy-sub").text().includes("Debt"), "the central-bank debt shows");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_resources_tab_shows_reserves_value_and_consumption() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
modal.show(
|
||
{ id: 1, name: "Lyon" },
|
||
{
|
||
budget: 1.0e9,
|
||
gdp: 1.0e9,
|
||
resources: {
|
||
stock: { food: 1000, steel: 2000, luxury: 0, hightech: 50 },
|
||
consumption: { food: 100, steel: 200, luxury: 10, hightech: 2, energy: 2500 },
|
||
value: 123456,
|
||
},
|
||
}
|
||
);
|
||
env.$("#modal-city .tab[data-tab=resources]").click();
|
||
this.assertTrue(env.$("#city-tab-resources").hasClass("active"));
|
||
this.assertTrue(
|
||
env.$("#city-resources-sub").text().includes("123 456"),
|
||
"the reserve value shows"
|
||
);
|
||
const text = env.$("#city-resources-list").text();
|
||
this.assertTrue(text.includes("Food"), "food is listed");
|
||
this.assertTrue(text.includes("Steel"), "steel is listed");
|
||
this.assertTrue(text.includes("Energy"), "energy is listed");
|
||
this.assertTrue(text.includes("2.5 MWh"), "the daily power draw is shown");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_people_tab_reports_resource_shortages() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new CityModal();
|
||
modal.show(
|
||
{ id: 1, name: "Lyon" },
|
||
{
|
||
budget: 1.0e9,
|
||
gdp: 1.0e9,
|
||
ethnicMakeup: [],
|
||
approval: 0.5,
|
||
shortage: { steel: { fraction: 0.4, amount: 1200 } },
|
||
}
|
||
);
|
||
env.$("#modal-city .tab[data-tab=people]").click();
|
||
this.assertTrue(env.$("#city-tab-people").hasClass("active"));
|
||
const text = env.$("#city-people-list").text();
|
||
this.assertTrue(text.includes("Resource shortages"), "the shortage section shows");
|
||
this.assertTrue(text.includes("Steel"), "the short resource is named");
|
||
this.assertTrue(text.includes("1200"), "the amount it is short by is shown");
|
||
this.assertTrue(text.includes("40%"), "the share of need is shown");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
}
|
||
|
||
export class NationModalTest extends TestCase {
|
||
async test_government_and_technology_tabs() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
let government = null;
|
||
let technology = null;
|
||
modal.onGovernment = (index) => {
|
||
government = index;
|
||
};
|
||
modal.onFocusTechnology = (index) => {
|
||
technology = index;
|
||
};
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6);
|
||
this.assertSize(env.$("#government-list .row-card"), GOVERNMENTS.length);
|
||
this.assertSize(env.$("#technology-list .row-card"), TECHNOLOGIES.length);
|
||
|
||
const governmentRows = env.$("#government-list .row-card");
|
||
this.assertTrue(governmentRows.eq(0).find(".actions button").prop("disabled"), "current government is locked");
|
||
governmentRows.eq(1).find(".actions button").click();
|
||
this.assertEqual(government, 1);
|
||
|
||
// A prerequisite-gated technology starts locked.
|
||
const method = TECHNOLOGIES.findIndex((t) => t.id === "scientific_method");
|
||
const automation = TECHNOLOGIES.findIndex((t) => t.id === "industrial_automation");
|
||
const techRows = env.$("#technology-list .row-card");
|
||
this.assertEqual(techRows.eq(automation).find(".actions button").text(), "Locked");
|
||
|
||
// Researching its prerequisite unlocks it.
|
||
modal.refresh(0, new Set([method]), 1.0e9, 1.0e15, 1.0e6);
|
||
this.assertTrue(techRows.eq(method).find(".actions button").text().startsWith("Researched"));
|
||
this.assertTrue(techRows.eq(automation).find(".actions button").text().startsWith("Focus"));
|
||
techRows.eq(automation).find(".actions button").click();
|
||
this.assertEqual(technology, automation);
|
||
|
||
env.$("#modal-nation .tab[data-tab=technology]").click();
|
||
this.assertTrue(env.$("#tab-technology").hasClass("active"));
|
||
env.$("#modal-nation .tab[data-tab=government]").click();
|
||
this.assertTrue(env.$("#tab-government").hasClass("active"));
|
||
modal.close();
|
||
this.assertTrue(env.$("#modal-nation").hasClass("hidden"));
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_technology_theme_tabs_filter_the_list() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6);
|
||
const $themes = env.$("#technology-themes .subtab");
|
||
this.assertGreater($themes.length, 1, "the technologies are split into themes");
|
||
const method = TECHNOLOGIES.findIndex((t) => t.id === "scientific_method");
|
||
const automation = TECHNOLOGIES.findIndex((t) => t.id === "industrial_automation");
|
||
const rows = env.$("#technology-list .row-card");
|
||
this.assertNotEqual(rows.eq(method).css("display"), "none", "science is the opening theme");
|
||
this.assertEqual(rows.eq(automation).css("display"), "none", "other themes start hidden");
|
||
$themes.filter((_index, element) => env.$(element).text() === "Economy").trigger("click");
|
||
this.assertEqual(rows.eq(method).css("display"), "none", "science is hidden");
|
||
this.assertNotEqual(rows.eq(automation).css("display"), "none", "the economy theme shows");
|
||
modal.close();
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_a_repeatable_technology_shows_its_level() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const method = TECHNOLOGIES.findIndex((t) => t.id === "scientific_method");
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set([method]), 1.0e9, 1.0e15, 1.0e6, {}, null, [], null, {
|
||
focus: -1,
|
||
progress: 0,
|
||
repeatCounts: { infantry_weapons: 3 },
|
||
});
|
||
const index = TECHNOLOGIES.findIndex((t) => t.id === "infantry_weapons");
|
||
const name = env.$("#technology-list .row-card").eq(index).find(".name").text();
|
||
this.assertTrue(name.includes("Level 3"), `the level is shown: ${name}`);
|
||
const text = env.$("#technology-list .row-card").eq(index).find(".cost").text();
|
||
this.assertTrue(text.startsWith("Cost"), "the next level is priced");
|
||
modal.close();
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_resources_tab_lists_stores_needs_and_the_market() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const summary = {
|
||
stock: { steel: 1000, food: 2_000_000, luxury: 5000, hightech: 12 },
|
||
need: { steel: 10, food: 20, luxury: 30, hightech: 0 },
|
||
production: { steel: 5, food: 0, luxury: 0, hightech: 1 },
|
||
consumed: { steel: 15, food: 25, luxury: 35, hightech: 2, energy: 1.1e9 },
|
||
energy: { need: 1.0e9, supply: 2.0e9 },
|
||
trade: { imports: { steel: 40 }, exports: { steel: 7 } },
|
||
prices: {},
|
||
};
|
||
const market = [
|
||
{ id: "energy", price: 0.003, supply: 1.0e9, demand: 2.0e9 },
|
||
{ id: "steel", price: 600, supply: 100, demand: 200 },
|
||
{ id: "food", price: 300, supply: 50, demand: 60 },
|
||
{ id: "luxury", price: 60, supply: 0, demand: 10 },
|
||
{ id: "hightech", price: 800, supply: 0, demand: 0 },
|
||
];
|
||
modal.show(
|
||
GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 5,
|
||
{}, null, [], null, null, { summary, market }
|
||
);
|
||
env.$("#modal-nation .tab[data-tab=resources]").click();
|
||
this.assertTrue(env.$("#tab-resources").hasClass("active"), "the tab opens");
|
||
const rows = env.$("#resources-list .resources-table tbody tr");
|
||
this.assertSize(rows, 5, "one row for every resource");
|
||
const energy = rows.eq(0);
|
||
this.assertTrue(energy.find(".name").text().includes("Energy"), "energy leads the list");
|
||
this.assertEqual(energy.find("td").eq(1).text(), "—", "energy has no store");
|
||
const steel = rows.eq(1);
|
||
this.assertTrue(steel.find(".name").text().includes("Steel"));
|
||
this.assertTrue(steel.find("td").eq(2).text().includes("15"), "consumption is shown");
|
||
this.assertTrue(steel.find("td").eq(4).text().includes("7"), "exports are shown");
|
||
this.assertTrue(steel.find("td").eq(5).text().includes("40"), "imports are shown");
|
||
this.assertTrue(steel.find("td").eq(6).text().includes("600"), "the steel price is shown");
|
||
this.assertTrue(steel.find("td").eq(7).text().length > 0, "world supply is shown");
|
||
modal.refresh(
|
||
0, new Set(), 1.0e9, 1.0e15, 5, {}, null, null, null, null,
|
||
{ summary, market }
|
||
);
|
||
this.assertSize(env.$("#resources-list .resources-table tbody tr"), 5, "refreshing keeps the rows");
|
||
modal.close();
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_resources_tab_ranks_major_exporters_and_importers() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const summary = {
|
||
stock: { steel: 0, food: 0, luxury: 0, hightech: 0 },
|
||
need: { steel: 0, food: 0, luxury: 0, hightech: 0 },
|
||
production: { steel: 0, food: 0, luxury: 0, hightech: 0 },
|
||
consumed: { steel: 0, food: 0, luxury: 0, hightech: 0, energy: 0 },
|
||
energy: { need: 0, supply: 0 },
|
||
trade: { imports: {}, exports: {} },
|
||
prices: {},
|
||
};
|
||
const trade = [
|
||
{ civ: 0, imports: { steel: 10 }, exports: { steel: 100 } },
|
||
{ civ: 1, imports: { steel: 50 }, exports: { steel: 5 } },
|
||
];
|
||
const civs = [{ name: "France" }, { name: "Britain" }];
|
||
modal.show(
|
||
GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 5,
|
||
{}, null, [], null, null, { summary, market: [], trade, civs }
|
||
);
|
||
env.$("#modal-nation .tab[data-tab=resources]").click();
|
||
env.$("#resources-subtabs .subtab[data-view=leaders]").click();
|
||
const rows = env.$("#resource-trade-list .resources-table tbody tr");
|
||
this.assertSize(rows, 5, "one row for every resource");
|
||
const steel = rows.eq(1);
|
||
this.assertTrue(steel.find("td").eq(1).text().includes("France"), "the major exporter leads");
|
||
this.assertTrue(steel.find("td").eq(3).text().includes("Britain"), "the major importer leads");
|
||
modal.close();
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_a_focused_technology_shows_a_progress_bar() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const method = TECHNOLOGIES.findIndex((t) => t.id === "scientific_method");
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 5, {}, null, [], null, {
|
||
focus: method,
|
||
progress: 10,
|
||
repeatCounts: {},
|
||
});
|
||
const card = env.$("#technology-list .row-card").eq(method);
|
||
this.assertTrue(card.find(".tech-progress-track").length > 0, "the focus has a bar");
|
||
this.assertEqual(
|
||
card.find(".tech-progress-text").text(),
|
||
`10 / ${groupDigits(technologyCost(TECHNOLOGIES[method]))}`,
|
||
"X / Y beside it"
|
||
);
|
||
this.assertEqual(card.find(".actions button").text(), "Focused", "no cost on the button");
|
||
modal.close();
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_military_technology_effects_are_readable_text() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 5);
|
||
const infantry = TECHNOLOGIES.findIndex((t) => t.id === "infantry_weapons");
|
||
this.assertEqual(
|
||
env.$("#technology-list .row-card").eq(infantry).find(".effects").text(),
|
||
"+1.0% infantry attack"
|
||
);
|
||
modal.close();
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_reopening_rebuilds_rows_instead_of_stacking_them() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
let technology = null;
|
||
modal.onFocusTechnology = (index) => {
|
||
technology = index;
|
||
};
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 0);
|
||
modal.close();
|
||
// Reopen with enough research to afford the first technology.
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6);
|
||
this.assertSize(env.$("#government-list .row-card"), GOVERNMENTS.length, "no stacked governments");
|
||
this.assertSize(env.$("#technology-list .row-card"), TECHNOLOGIES.length, "no stacked technologies");
|
||
const button = env.$("#technology-list .row-card").first().find(".actions button");
|
||
this.assertFalse(button.prop("disabled"), "the rebuilt button reflects the new budget");
|
||
button.click();
|
||
this.assertEqual(technology, 0);
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_budget_tab_shows_monthly_income_and_expenses() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const month = (overrides) => {
|
||
const income = overrides.income || 0;
|
||
return {
|
||
monthIndex: 24000,
|
||
isCurrent: true,
|
||
label: "January 2000",
|
||
income,
|
||
taxes: { sales: income, export: 0, import: 0 },
|
||
sales: 0,
|
||
totalCash: 0,
|
||
totalEconomic: 0,
|
||
net: 0,
|
||
expenses: [],
|
||
resourceTrade: [],
|
||
...overrides,
|
||
};
|
||
};
|
||
const finances = {
|
||
months: [
|
||
month({
|
||
monthIndex: 23999,
|
||
isCurrent: false,
|
||
label: "December 1999",
|
||
income: 500,
|
||
totalCash: 400,
|
||
totalEconomic: 1200,
|
||
net: 100,
|
||
expenses: [["buildings", 400, 1200]],
|
||
}),
|
||
month({
|
||
income: 1035,
|
||
sales: 60,
|
||
totalCash: 550,
|
||
totalEconomic: 900,
|
||
net: 545,
|
||
expenses: [
|
||
["buildings", 400, 700, [
|
||
["steel", 250, [["Barracks", 250]]],
|
||
["hightech", 150, [["Laboratory", 150]]],
|
||
]],
|
||
["units", 150, 200, []],
|
||
],
|
||
resourceTrade: [["steel", 220, 0], ["food", 0, 90]],
|
||
}),
|
||
],
|
||
cities: [],
|
||
};
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6, finances);
|
||
env.$("#modal-nation .tab[data-tab=budget]").click();
|
||
this.assertTrue(env.$("#tab-budget").hasClass("active"));
|
||
this.assertSize(env.$("#budget-list table.budget-table"), 1);
|
||
|
||
const text = env.$("#budget-list").text();
|
||
this.assertTrue(text.includes("National sales tax"), "the month's taxes are shown");
|
||
this.assertTrue(text.includes("+¤1 035"), "the tax take is shown");
|
||
this.assertTrue(text.includes("Resource sales"), "resource sales are shown");
|
||
this.assertTrue(text.includes("Building upkeep"), "a building category is listed");
|
||
this.assertTrue(text.includes("−¤700"), "the rightmost column is the market value");
|
||
this.assertTrue(text.includes("cash −¤400"), "the cash the treasury paid is noted");
|
||
this.assertTrue(text.includes("Unit upkeep"), "a unit category is listed");
|
||
this.assertTrue(text.includes("Bought Steel"), "a bought resource is listed");
|
||
this.assertTrue(text.includes("Sold Food"), "a sold resource is listed");
|
||
this.assertTrue(text.includes("TOTAL"), "a total row is present");
|
||
this.assertTrue(text.includes("+¤545"), "the total carries the month net");
|
||
this.assertTrue(env.$("#budget-sub").text().includes("Treasury"));
|
||
this.assertTrue(env.$("#budget-sub").text().includes("January 2000"), "the month is named");
|
||
|
||
// Expanding an upkeep row names the resources it bought and the buildings
|
||
// that consumed them.
|
||
env.$("#budget-list tr .budget-name.clickable").first().click();
|
||
const expanded = env.$("#budget-list").text();
|
||
this.assertTrue(expanded.includes("Steel"), "the expanded row names steel");
|
||
this.assertTrue(expanded.includes("−¤250"), "and what it paid for it");
|
||
this.assertTrue(expanded.includes("Barracks"), "and the building that used it");
|
||
|
||
// The pager steps back to the previous month's digest.
|
||
env.$("#budget-months .budget-month-nav").first().click();
|
||
this.assertTrue(
|
||
env.$("#budget-sub").text().includes("December 1999"),
|
||
"the pager names the older month"
|
||
);
|
||
|
||
modal.refresh(0, new Set(), 1.0e9, 1.0e15, 1.0e6, {
|
||
months: [month({
|
||
income: 100,
|
||
totalCash: 400,
|
||
totalEconomic: 400,
|
||
net: -300,
|
||
expenses: [["buildings", 400, 400]],
|
||
})],
|
||
cities: [],
|
||
});
|
||
const refreshed = env.$("#budget-list").text();
|
||
this.assertTrue(refreshed.includes("−¤300"), "the total updates");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_cities_tab_lists_regions_with_their_tax() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const finances = {
|
||
income: { rate: 0.001, base: 0, modifier: 0, total: 0, sources: [], regions: [] },
|
||
buildingUpkeep: { total: 0, sources: [], groups: [] },
|
||
unitUpkeep: { total: 0, sources: [], groups: [] },
|
||
net: 0,
|
||
cities: [
|
||
{ id: 1, civ: 0, name: "Paris", isCapital: true, population: 1.0e6, gdp: 1.0e10, income: 300 },
|
||
{ id: 2, civ: 0, name: "Lille", isCapital: false, population: 5.0e5, gdp: 4.0e9, income: 120 },
|
||
{ id: 3, civ: 1, name: "London", isCapital: true, population: 9.0e5, gdp: 8.0e9, income: 240 },
|
||
],
|
||
};
|
||
modal.show(GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6, finances, {
|
||
civs: [{ name: "France" }, { name: "Britain" }],
|
||
localCiv: 0,
|
||
relations: [],
|
||
stats: [],
|
||
});
|
||
env.$("#modal-nation .tab[data-tab=cities]").click();
|
||
this.assertTrue(env.$("#tab-cities").hasClass("active"));
|
||
const text = env.$("#cities-list").text();
|
||
this.assertTrue(text.includes("Paris"), "own regions are listed");
|
||
this.assertTrue(text.includes("Lille"), "every own region is listed");
|
||
this.assertFalse(text.includes("London"), "foreign regions are hidden");
|
||
this.assertTrue(text.includes("TOTAL"), "the region totals are summed");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_diplomacy_tab_lists_nations_and_declares_war() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
let declared = null;
|
||
modal.onDeclareWar = (index) => {
|
||
declared = index;
|
||
};
|
||
const civs = [{ name: "France" }, { name: "Britain" }, { name: "Poland" }];
|
||
const relations = [[0, 1, "peace"], [0, 2, "war"], [1, 2, "peace"]];
|
||
const stats = [
|
||
{ population: 2.0e6, gdp: 5.0e9, gdpPerCapita: 2500 },
|
||
{ population: 1.5e6, gdp: 3.0e9, gdpPerCapita: 2000 },
|
||
{ population: 1.0e6, gdp: 1.5e9, gdpPerCapita: 1500 },
|
||
];
|
||
modal.show(
|
||
GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6, {},
|
||
{ civs, localCiv: 0, relations, stats }
|
||
);
|
||
env.$("#modal-nation .tab[data-tab=diplomacy]").click();
|
||
this.assertTrue(env.$("#tab-diplomacy").hasClass("active"));
|
||
|
||
const rows = env.$("#diplomacy-list tbody tr");
|
||
this.assertSize(rows, 3, "every nation, including ours, is listed");
|
||
this.assertTrue(rows.eq(0).find(".name").text() === "Britain", "alphabetical by default");
|
||
this.assertTrue(rows.eq(0).find(".status").text().includes("At peace"));
|
||
const numbers = rows.eq(0).find("td.numeric");
|
||
this.assertTrue(numbers.eq(0).text().includes("¤3B"), "Britain's GDP shows");
|
||
this.assertTrue(numbers.eq(1).text().includes("¤2K"), "Britain's GDP/capita shows");
|
||
this.assertTrue(numbers.eq(2).text().includes("1.5M"), "Britain's population shows");
|
||
|
||
const own = rows.eq(1);
|
||
this.assertTrue(own.find(".name").text() === "France", "our own nation is listed");
|
||
this.assertTrue(own.hasClass("local-nation"), "our row is highlighted");
|
||
this.assertTrue(own.find(".status").text().includes("Your nation"));
|
||
this.assertSize(own.find("button"), 0, "we cannot declare war on ourselves");
|
||
|
||
this.assertTrue(rows.eq(2).find(".name").text() === "Poland");
|
||
this.assertTrue(rows.eq(2).find(".status").text().includes("At war"));
|
||
this.assertTrue(rows.eq(2).find("button").prop("disabled"), "already at war");
|
||
this.assertTrue(env.$("#diplomacy-sub").text().includes("at war with 1"));
|
||
|
||
rows.eq(0).find("button").click();
|
||
this.assertEqual(declared, 1);
|
||
modal.close();
|
||
this.assertTrue(env.$("#modal-nation").hasClass("hidden"));
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_diplomacy_table_sorts_by_every_column() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const civs = [{ name: "France" }, { name: "Britain" }, { name: "Poland" }];
|
||
const stats = [
|
||
{ population: 1.0e6, gdp: 1.0e9, gdpPerCapita: 1000 },
|
||
{ population: 3.0e6, gdp: 2.0e9, gdpPerCapita: 2000 },
|
||
{ population: 2.0e6, gdp: 3.0e9, gdpPerCapita: 3000 },
|
||
];
|
||
modal.show(
|
||
GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6, {},
|
||
{ civs, localCiv: 0, relations: [], stats }
|
||
);
|
||
const names = () => env.$("#diplomacy-list tbody tr .name")
|
||
.map((_, el) => env.$(el).text()).get();
|
||
this.assertEqual(names(), ["Britain", "France", "Poland"], "alphabetical by default");
|
||
this.assertTrue(env.$("#diplomacy-list th[data-sort=name]").hasClass("sorted-asc"));
|
||
|
||
// GDP ascending first, descending on the second click.
|
||
env.$("#diplomacy-list th[data-sort=gdp]").click();
|
||
this.assertEqual(names(), ["France", "Britain", "Poland"]);
|
||
this.assertTrue(env.$("#diplomacy-list th[data-sort=gdp]").hasClass("sorted-asc"));
|
||
env.$("#diplomacy-list th[data-sort=gdp]").click();
|
||
this.assertEqual(names(), ["Poland", "Britain", "France"]);
|
||
this.assertTrue(env.$("#diplomacy-list th[data-sort=gdp]").hasClass("sorted-desc"));
|
||
|
||
// A different column starts ascending.
|
||
env.$("#diplomacy-list th[data-sort=population]").click();
|
||
this.assertEqual(names(), ["France", "Poland", "Britain"]);
|
||
this.assertTrue(env.$("#diplomacy-list th[data-sort=population]").hasClass("sorted-asc"));
|
||
|
||
// Back to alphabetical.
|
||
env.$("#diplomacy-list th[data-sort=name]").click();
|
||
this.assertEqual(names(), ["Britain", "France", "Poland"]);
|
||
modal.close();
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_economy_tab_shows_private_cash_central_bank_and_rates() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const money = {
|
||
viewerCiv: 0,
|
||
currency: { code: "FRF", symbol: "₣", name: "French Franc" },
|
||
currencies: [
|
||
{ civ: 0, code: "FRF", symbol: "₣", name: "French Franc", value: 1 },
|
||
{ civ: 1, code: "GBP", symbol: "£", name: "British Pound", value: 1 },
|
||
],
|
||
exchangeRates: [
|
||
{ civ: 0, code: "FRF", symbol: "₣", name: "French Franc", rate: 1 },
|
||
{ civ: 1, code: "GBP", symbol: "£", name: "British Pound", rate: 0.85 },
|
||
],
|
||
centralBank: {
|
||
rate: 0.02,
|
||
currency: { code: "FRF", symbol: "₣", name: "French Franc" },
|
||
reserves: [{ code: "GBP", symbol: "£", name: "British Pound", amount: 1234 }],
|
||
loans: 987654,
|
||
},
|
||
privateCash: 5000,
|
||
// The trade-tax rates, the day's take and the commodity inflation.
|
||
taxes: {
|
||
sales: { rate: 0.2, resources: { steel: 0.1 } },
|
||
export: { rate: 0.05, resources: {} },
|
||
import: { rate: 0.05, resources: {} },
|
||
},
|
||
takeTax: { sales: 1200, export: 300, import: 100 },
|
||
commodityInflation: 0.0123,
|
||
cities: [{ id: 1, civ: 0, name: "Paris", cashValue: 5000 }],
|
||
currencyHoldings: {
|
||
code: "FRF",
|
||
symbol: "₣",
|
||
name: "French Franc",
|
||
value: 1,
|
||
treasury: 1000,
|
||
treasuryDebt: 0,
|
||
own: [{ cityId: 1, name: "Paris", civ: 0, civName: "France", amount: 5000 }],
|
||
ownTotal: 5000,
|
||
foreign: [{ cityId: 2, name: "London", civ: 1, civName: "Britain", amount: 700 }],
|
||
foreignTotal: 700,
|
||
banks: [{ civ: 1, name: "Britain", amount: 1234 }],
|
||
bankTotal: 1234,
|
||
total: 7934,
|
||
},
|
||
};
|
||
const resourcesInfo = {
|
||
summary: {
|
||
stock: {},
|
||
need: {},
|
||
production: {},
|
||
consumed: { steel: 1200, food: 10, luxury: 0, hightech: 0, energy: 0 },
|
||
external: {
|
||
buy: { steel: { qty: 300, value: 180_000 } },
|
||
sell: { food: { qty: 40, value: 12_000 } },
|
||
},
|
||
prices: {},
|
||
},
|
||
market: [],
|
||
};
|
||
modal.show(
|
||
GOVERNMENTS, 0, TECHNOLOGIES, new Set(), 1.0e9, 1.0e15, 1.0e6,
|
||
{ months: [], cities: [] }, null, [], null, null, resourcesInfo, money
|
||
);
|
||
env.$("#modal-nation .tab[data-tab=economy]").click();
|
||
this.assertTrue(env.$("#tab-economy").hasClass("active"));
|
||
const summary = env.$("#economy-summary").text();
|
||
this.assertTrue(summary.includes("Paris"), "the region is listed");
|
||
this.assertTrue(summary.includes("5 000"), "its private cash is shown");
|
||
|
||
env.$("#economy-subtabs .subtab[data-view=taxes]").click();
|
||
const taxesText = env.$("#economy-taxes").text();
|
||
this.assertTrue(taxesText.includes("Sales tax"), "the sales tax is listed");
|
||
this.assertTrue(taxesText.includes("Export tariff"), "the export tariff is listed");
|
||
this.assertTrue(taxesText.includes("Import tariff"), "the import tariff is listed");
|
||
this.assertEqual(
|
||
env.$("#economy-taxes .tax-input[data-kind=sales]").first().val(), "20.00",
|
||
"the default sales rate is shown"
|
||
);
|
||
this.assertEqual(
|
||
env.$("#economy-taxes .tax-input[data-kind=sales][data-resource='steel']").val(), "10.00",
|
||
"the per-resource override is shown"
|
||
);
|
||
this.assertTrue(
|
||
env.$("#economy-sub").text().includes("1 600"), "the day's total take is shown"
|
||
);
|
||
|
||
env.$("#economy-subtabs .subtab[data-view=centralbank]").click();
|
||
const bank = env.$("#economy-central-bank").text();
|
||
this.assertTrue(bank.includes("British Pound"), "the foreign reserve is listed");
|
||
this.assertTrue(bank.includes("987 654"), "the outstanding loans are listed");
|
||
this.assertTrue(bank.includes("Commodity inflation"), "the inflation indicator is shown");
|
||
this.assertTrue(env.$("#cb-rate").length === 1, "the rate input is present");
|
||
|
||
env.$("#economy-subtabs .subtab[data-view=rates]").click();
|
||
this.assertTrue(env.$("#economy-rates").text().includes("British Pound"), "the rate table shows");
|
||
this.assertTrue(env.$("#economy-rates").text().includes("0.8500"), "the rate is shown");
|
||
|
||
env.$("#economy-subtabs .subtab[data-view=consumption]").click();
|
||
const consumption = env.$("#economy-consumption").text();
|
||
this.assertTrue(consumption.includes("Steel"), "the consumed resource is listed");
|
||
this.assertTrue(consumption.includes("1200"), "its daily consumption is shown");
|
||
this.assertTrue(consumption.includes("180 000"), "what was spent abroad is shown");
|
||
this.assertTrue(consumption.includes("40"), "what was sold abroad is shown");
|
||
|
||
env.$("#economy-subtabs .subtab[data-view=currency]").click();
|
||
const currency = env.$("#economy-currency").text();
|
||
this.assertTrue(
|
||
env.$("#economy-sub").text().includes("French Franc"),
|
||
"the currency is named"
|
||
);
|
||
this.assertTrue(currency.includes("Paris"), "a home region holding it is listed");
|
||
this.assertTrue(currency.includes("London"), "a foreign region holding it is listed");
|
||
this.assertTrue(currency.includes("Central bank of Britain"), "a foreign bank is listed");
|
||
this.assertTrue(currency.includes("7 934"), "the total in circulation is shown");
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
}
|
||
|
||
export class ResourceTrendTest extends TestCase {
|
||
async test_resources_tab_marks_day_on_day_changes() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NationModal();
|
||
const info = (price, totalHours) => ({
|
||
totalHours,
|
||
summary: {
|
||
stock: { food: 100, steel: 100, luxury: 100, hightech: 0 },
|
||
consumed: { food: 10, steel: 10, luxury: 10, hightech: 0, energy: 100 },
|
||
production: { food: 10, steel: 10, luxury: 10, hightech: 0 },
|
||
energy: { need: 100, supply: 100 },
|
||
trade: { imports: {}, exports: {} },
|
||
},
|
||
market: [{ id: "food", price, prevPrice: price, supply: 1000, demand: 1000 }],
|
||
trade: [],
|
||
civs: [{ name: "France" }],
|
||
});
|
||
modal._renderResources(info(100, 0));
|
||
this.assertEqual(
|
||
env.$("#resources-list .stat-arrow").length, 0,
|
||
"the first day has no baseline to compare against"
|
||
);
|
||
modal._renderResources(info(120, 24));
|
||
this.assertTrue(
|
||
env.$("#resources-list .stat-arrow").length > 0, "the second day marks the changes"
|
||
);
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
}
|
||
|
||
export class ConfirmModalTest extends TestCase {
|
||
async test_confirm_runs_the_callback_and_cancel_does_not() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new ConfirmModal();
|
||
let confirmed = 0;
|
||
modal.show("Declare war?", "Marching in will declare war.", () => { confirmed += 1; });
|
||
this.assertTrue(modal.isShowing());
|
||
this.assertEqual(env.$("#confirm-title").text(), "Declare war?");
|
||
this.assertTrue(env.$("#confirm-message").text().includes("declare war"));
|
||
|
||
env.$("#confirm-cancel").click();
|
||
this.assertFalse(modal.isShowing());
|
||
this.assertEqual(confirmed, 0, "cancelling runs nothing");
|
||
|
||
modal.show("Again", "Sure?", () => { confirmed += 1; });
|
||
env.$("#confirm-ok").click();
|
||
this.assertEqual(confirmed, 1, "confirming runs the callback once");
|
||
this.assertFalse(modal.isShowing());
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
async test_close_button_cancels() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new ConfirmModal();
|
||
let confirmed = 0;
|
||
modal.show("T", "M", () => { confirmed += 1; });
|
||
env.$("#modal-confirm .modal-close").click();
|
||
this.assertEqual(confirmed, 0);
|
||
this.assertFalse(modal.isShowing());
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
}
|
||
|
||
export class NewsModalTest extends TestCase {
|
||
async test_lists_events_newest_first_with_dates() {
|
||
const env = await setupDom();
|
||
try {
|
||
const modal = new NewsModal();
|
||
const civs = [{ name: "France", demonym: "French" }, { name: "Britain", demonym: "British" }];
|
||
const news = [
|
||
{ id: 1, type: "war", actor: 0, target: 1, date: "1 January 2000, 00:00" },
|
||
{ id: 2, type: "capture", city: "Lyon", from: 1, to: 0, date: "2 January 2000, 05:00" },
|
||
];
|
||
modal.show(news, civs);
|
||
const items = env.$("#news-list .news-item");
|
||
this.assertSize(items, 2);
|
||
this.assertTrue(
|
||
items.eq(0).find(".news-text").text().includes("French troops have captured Lyon from the British")
|
||
);
|
||
this.assertTrue(items.eq(0).find(".news-date").text().includes("05:00"));
|
||
this.assertTrue(
|
||
items.eq(1).find(".news-text").text().includes("French leaders have declared war on Britain")
|
||
);
|
||
|
||
modal.refresh([], civs);
|
||
this.assertEqual(env.$("#news-list .news-item").length, 0);
|
||
this.assertTrue(env.$("#news-list").text().includes("No news"));
|
||
modal.close();
|
||
this.assertTrue(env.$("#modal-news").hasClass("hidden"));
|
||
} finally {
|
||
teardownDom(env);
|
||
}
|
||
}
|
||
|
||
test_news_names_the_actors_doing_the_action() {
|
||
const civs = [
|
||
{ name: "France", demonym: "French" },
|
||
{ name: "Vietnam", demonym: "Vietnamese" },
|
||
{ name: "Aotearoa", demonym: "New Zealander", adjective: "New Zealand" },
|
||
];
|
||
this.assertEqual(
|
||
describeNews({ type: "capture", city: "Saigon", from: 1, to: 0 }, civs),
|
||
"French troops have captured Saigon from the Vietnamese"
|
||
);
|
||
this.assertEqual(
|
||
describeNews({ type: "technology", civ: 0, name: "Radio" }, civs),
|
||
"French scientists have discovered Radio"
|
||
);
|
||
this.assertEqual(
|
||
describeNews({ type: "technology", civ: 0, name: "Railways", repeatable: true }, civs),
|
||
"French scientists have improved Railways"
|
||
);
|
||
this.assertEqual(
|
||
describeNews({ type: "war", actor: 0, target: 1 }, civs),
|
||
"French leaders have declared war on Vietnam"
|
||
);
|
||
this.assertEqual(
|
||
describeNews({ type: "policy", civ: 0, policy: "some_policy", ethnicity: 1 }, civs),
|
||
"French lawmakers have enacted some_policy for the Vietnamese"
|
||
);
|
||
this.assertEqual(
|
||
describeNews({ type: "join", player: "Alice", civ: 1 }, civs),
|
||
"Alice took control of Vietnam"
|
||
);
|
||
// Person-noun demonyms carry an explicit attributive form.
|
||
this.assertEqual(
|
||
describeNews({ type: "technology", civ: 2, name: "Radio" }, civs),
|
||
"New Zealand scientists have discovered Radio"
|
||
);
|
||
}
|
||
}
|