mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-30 21:42:20 +02:00
Merge remote-tracking branch 'upstream/beta' into move-use-type
This commit is contained in:
commit
e9bd0810ba
@ -1,172 +0,0 @@
|
|||||||
/**
|
|
||||||
* This script creates a test boilerplate file in the appropriate
|
|
||||||
* directory based on the type selected.
|
|
||||||
* @example npm run create-test
|
|
||||||
*/
|
|
||||||
|
|
||||||
import fs from "fs";
|
|
||||||
import inquirer from "inquirer";
|
|
||||||
import path from "path";
|
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
// Get the directory name of the current module file
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
const typeChoices = ["Move", "Ability", "Item", "Mystery Encounter"];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prompts the user to select a type via list.
|
|
||||||
* @returns {Promise<{selectedOption: string}>} the selected type
|
|
||||||
*/
|
|
||||||
async function promptTestType() {
|
|
||||||
const typeAnswer = await inquirer.prompt([
|
|
||||||
{
|
|
||||||
type: "list",
|
|
||||||
name: "selectedOption",
|
|
||||||
message: "What type of test would you like to create:",
|
|
||||||
choices: [...typeChoices, "EXIT"],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (typeAnswer.selectedOption === "EXIT") {
|
|
||||||
console.log("Exiting...");
|
|
||||||
return process.exit();
|
|
||||||
}
|
|
||||||
if (!typeChoices.includes(typeAnswer.selectedOption)) {
|
|
||||||
console.error(`Please provide a valid type (${typeChoices.join(", ")})!`);
|
|
||||||
return await promptTestType();
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeAnswer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prompts the user to provide a file name.
|
|
||||||
* @param {string} selectedType
|
|
||||||
* @returns {Promise<{userInput: string}>} the selected file name
|
|
||||||
*/
|
|
||||||
async function promptFileName(selectedType) {
|
|
||||||
const fileNameAnswer = await inquirer.prompt([
|
|
||||||
{
|
|
||||||
type: "input",
|
|
||||||
name: "userInput",
|
|
||||||
message: `Please provide the name of the ${selectedType}:`,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!fileNameAnswer.userInput || fileNameAnswer.userInput.trim().length === 0) {
|
|
||||||
console.error("Please provide a valid file name!");
|
|
||||||
return await promptFileName(selectedType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileNameAnswer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the interactive create-test "CLI"
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function runInteractive() {
|
|
||||||
const typeAnswer = await promptTestType();
|
|
||||||
const fileNameAnswer = await promptFileName(typeAnswer.selectedOption);
|
|
||||||
|
|
||||||
const type = typeAnswer.selectedOption.toLowerCase();
|
|
||||||
// Convert fileName from kebab-case or camelCase to snake_case
|
|
||||||
const fileName = fileNameAnswer.userInput
|
|
||||||
.replace(/-+/g, "_") // Convert kebab-case (dashes) to underscores
|
|
||||||
.replace(/([a-z])([A-Z])/g, "$1_$2") // Convert camelCase to snake_case
|
|
||||||
.replace(/\s+/g, "_") // Replace spaces with underscores
|
|
||||||
.toLowerCase(); // Ensure all lowercase
|
|
||||||
// Format the description for the test case
|
|
||||||
|
|
||||||
const formattedName = fileName.replace(/_/g, " ").replace(/\b\w/g, char => char.toUpperCase());
|
|
||||||
// Determine the directory based on the type
|
|
||||||
let dir;
|
|
||||||
let description;
|
|
||||||
switch (type) {
|
|
||||||
case "move":
|
|
||||||
dir = path.join(__dirname, "test", "moves");
|
|
||||||
description = `Moves - ${formattedName}`;
|
|
||||||
break;
|
|
||||||
case "ability":
|
|
||||||
dir = path.join(__dirname, "test", "abilities");
|
|
||||||
description = `Abilities - ${formattedName}`;
|
|
||||||
break;
|
|
||||||
case "item":
|
|
||||||
dir = path.join(__dirname, "test", "items");
|
|
||||||
description = `Items - ${formattedName}`;
|
|
||||||
break;
|
|
||||||
case "mystery encounter":
|
|
||||||
dir = path.join(__dirname, "test", "mystery-encounter", "encounters");
|
|
||||||
description = `Mystery Encounter - ${formattedName}`;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error(`Invalid type. Please use one of the following: ${typeChoices.join(", ")}.`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define the content template
|
|
||||||
const content = `import { Abilities } from "#enums/abilities";
|
|
||||||
import { Moves } from "#enums/moves";
|
|
||||||
import { Species } from "#enums/species";
|
|
||||||
import GameManager from "#test/testUtils/gameManager";
|
|
||||||
import Phaser from "phaser";
|
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
||||||
|
|
||||||
describe("${description}", () => {
|
|
||||||
let phaserGame: Phaser.Game;
|
|
||||||
let game: GameManager;
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
phaserGame = new Phaser.Game({
|
|
||||||
type: Phaser.HEADLESS,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
game.phaseInterceptor.restoreOg();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
game = new GameManager(phaserGame);
|
|
||||||
game.override
|
|
||||||
.moveset([ Moves.SPLASH ])
|
|
||||||
.ability(Abilities.BALL_FETCH)
|
|
||||||
.battleType("single")
|
|
||||||
.disableCrits()
|
|
||||||
.enemySpecies(Species.MAGIKARP)
|
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
|
||||||
.enemyMoveset(Moves.SPLASH);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should do X", async () => {
|
|
||||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
|
||||||
|
|
||||||
game.move.select(Moves.SPLASH);
|
|
||||||
await game.phaseInterceptor.to("BerryPhase");
|
|
||||||
|
|
||||||
expect(true).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Ensure the directory exists
|
|
||||||
if (!fs.existsSync(dir)) {
|
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the file with the given name
|
|
||||||
const filePath = path.join(dir, `${fileName}.test.ts`);
|
|
||||||
|
|
||||||
if (fs.existsSync(filePath)) {
|
|
||||||
console.error(`File "${fileName}.test.ts" already exists.`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the template content to the file
|
|
||||||
fs.writeFileSync(filePath, content, "utf8");
|
|
||||||
|
|
||||||
console.log(`File created at: ${filePath}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
runInteractive();
|
|
@ -13,6 +13,7 @@
|
|||||||
"test:cov": "vitest run --coverage --no-isolate",
|
"test:cov": "vitest run --coverage --no-isolate",
|
||||||
"test:watch": "vitest watch --coverage --no-isolate",
|
"test:watch": "vitest watch --coverage --no-isolate",
|
||||||
"test:silent": "vitest run --silent --no-isolate",
|
"test:silent": "vitest run --silent --no-isolate",
|
||||||
|
"test:create": "node scripts/create-test/create-test.js",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"eslint": "eslint --fix .",
|
"eslint": "eslint --fix .",
|
||||||
"eslint-ci": "eslint .",
|
"eslint-ci": "eslint .",
|
||||||
@ -21,7 +22,6 @@
|
|||||||
"docs": "typedoc",
|
"docs": "typedoc",
|
||||||
"depcruise": "depcruise src",
|
"depcruise": "depcruise src",
|
||||||
"depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg",
|
"depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg",
|
||||||
"create-test": "node ./create-test-boilerplate.js",
|
|
||||||
"postinstall": "npx lefthook install && npx lefthook run post-merge",
|
"postinstall": "npx lefthook install && npx lefthook run post-merge",
|
||||||
"update-version:patch": "npm version patch --force --no-git-tag-version",
|
"update-version:patch": "npm version patch --force --no-git-tag-version",
|
||||||
"update-version:minor": "npm version minor --force --no-git-tag-version",
|
"update-version:minor": "npm version minor --force --no-git-tag-version",
|
||||||
|
147
scripts/create-test/create-test.js
Normal file
147
scripts/create-test/create-test.js
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
* This script creates a test boilerplate file in the appropriate
|
||||||
|
* directory based on the type selected.
|
||||||
|
* @example npm run test:create
|
||||||
|
*/
|
||||||
|
|
||||||
|
import chalk from "chalk";
|
||||||
|
import inquirer from "inquirer";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
//#region Constants
|
||||||
|
|
||||||
|
const version = "2.0.1";
|
||||||
|
// Get the directory name of the current module file
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const projectRoot = path.join(__dirname, "..", "..");
|
||||||
|
const boilerplateFilePath = path.join(__dirname, "test-boilerplate.ts");
|
||||||
|
const choices = [
|
||||||
|
{ label: "Move", dir: "moves" },
|
||||||
|
{ label: "Ability", dir: "abilities" },
|
||||||
|
{ label: "Item", dir: "items" },
|
||||||
|
{ label: "Mystery Encounter", dir: "mystery-encounter/encounters" },
|
||||||
|
{ label: "Utils", dir: "utils" },
|
||||||
|
{ label: "UI", dir: "ui" },
|
||||||
|
];
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
//#region Functions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to a given folder in the test directory
|
||||||
|
* @param {...string} folders the subfolders to append to the base path
|
||||||
|
* @returns {string} the path to the requested folder
|
||||||
|
*/
|
||||||
|
function getTestFolderPath(...folders) {
|
||||||
|
return path.join(projectRoot, "test", ...folders);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to select a type via list.
|
||||||
|
* @returns {Promise<{selectedOption: {label: string, dir: string}}>} the selected type
|
||||||
|
*/
|
||||||
|
async function promptTestType() {
|
||||||
|
const typeAnswer = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: "list",
|
||||||
|
name: "selectedOption",
|
||||||
|
message: "What type of test would you like to create:",
|
||||||
|
choices: [...choices.map(choice => ({ name: choice.label, value: choice })), "EXIT"],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (typeAnswer.selectedOption === "EXIT") {
|
||||||
|
console.log("Exiting...");
|
||||||
|
return process.exit();
|
||||||
|
}
|
||||||
|
if (!choices.some(choice => choice.dir === typeAnswer.selectedOption.dir)) {
|
||||||
|
console.error(`Please provide a valid type: (${choices.map(choice => choice.label).join(", ")})!`);
|
||||||
|
return await promptTestType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeAnswer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user to provide a file name.
|
||||||
|
* @param {string} selectedType
|
||||||
|
* @returns {Promise<{userInput: string}>} the selected file name
|
||||||
|
*/
|
||||||
|
async function promptFileName(selectedType) {
|
||||||
|
/** @type {{userInput: string}} */
|
||||||
|
const fileNameAnswer = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
name: "userInput",
|
||||||
|
message: `Please provide the name of the ${selectedType}:`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!fileNameAnswer.userInput || fileNameAnswer.userInput.trim().length === 0) {
|
||||||
|
console.error("Please provide a valid file name!");
|
||||||
|
return await promptFileName(selectedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileNameAnswer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the interactive test:create "CLI"
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async function runInteractive() {
|
||||||
|
console.group(chalk.grey(`Create Test - v${version}\n`));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const typeAnswer = await promptTestType();
|
||||||
|
const fileNameAnswer = await promptFileName(typeAnswer.selectedOption.label);
|
||||||
|
|
||||||
|
const type = typeAnswer.selectedOption;
|
||||||
|
// Convert fileName from snake_case or camelCase to kebab-case
|
||||||
|
const fileName = fileNameAnswer.userInput
|
||||||
|
.replace(/_+/g, "-") // Convert snake_case (underscore) to kebab-case (dashes)
|
||||||
|
.replace(/([a-z])([A-Z])/g, "$1-$2") // Convert camelCase to kebab-case
|
||||||
|
.replace(/\s+/g, "-") // Replace spaces with dashes
|
||||||
|
.toLowerCase(); // Ensure all lowercase
|
||||||
|
// Format the description for the test case
|
||||||
|
|
||||||
|
const formattedName = fileName.replace(/-/g, " ").replace(/\b\w/g, char => char.toUpperCase());
|
||||||
|
// Determine the directory based on the type
|
||||||
|
const dir = getTestFolderPath(type.dir);
|
||||||
|
const description = `${type.label} - ${formattedName}`;
|
||||||
|
|
||||||
|
// Define the content template
|
||||||
|
const content = fs.readFileSync(boilerplateFilePath, "utf8").replace("{{description}}", description);
|
||||||
|
|
||||||
|
// Ensure the directory exists
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the file with the given name
|
||||||
|
const filePath = path.join(dir, `${fileName}.test.ts`);
|
||||||
|
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
console.error(chalk.red.bold(`\n✗ File "${fileName}.test.ts" already exists!\n`));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the template content to the file
|
||||||
|
fs.writeFileSync(filePath, content, "utf8");
|
||||||
|
|
||||||
|
console.log(chalk.green.bold(`\n✔ File created at: test/${type.dir}/${fileName}.test.ts\n`));
|
||||||
|
console.groupEnd();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(chalk.red("✗ Error: ", err.message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
//#region Run
|
||||||
|
|
||||||
|
runInteractive();
|
||||||
|
|
||||||
|
//#endregion
|
44
scripts/create-test/test-boilerplate.ts
Normal file
44
scripts/create-test/test-boilerplate.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { AbilityId } from "#enums/ability-id";
|
||||||
|
import { MoveId } from "#enums/move-id";
|
||||||
|
import { SpeciesId } from "#enums/species-id";
|
||||||
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("{{description}}", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.ability(AbilityId.BALL_FETCH)
|
||||||
|
.battleStyle("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(SpeciesId.MAGIKARP)
|
||||||
|
.enemyAbility(AbilityId.BALL_FETCH)
|
||||||
|
.enemyMoveset(MoveId.SPLASH)
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemyLevel(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should do X", async () => {
|
||||||
|
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||||
|
|
||||||
|
game.move.use(MoveId.SPLASH);
|
||||||
|
|
||||||
|
await game.toEndOfTurn();
|
||||||
|
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user