mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-19 13:59:27 +02:00
Reverted changes to positional tag battle flyout
This commit is contained in:
parent
4de3226d99
commit
8383df1855
@ -1,7 +1,5 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { DelayedAttackTag, type PositionalTag, WishTag } from "#data/positional-tags/positional-tag";
|
||||
import { PositionalTagType } from "#enums/positional-tag-type";
|
||||
import { PositionalTagAddedEvent } from "#events/arena";
|
||||
import type { ObjectValues } from "#types/type-helpers";
|
||||
import type { Constructor } from "#utils/common";
|
||||
|
||||
@ -22,12 +20,7 @@ export function loadPositionalTag<T extends PositionalTagType>(data: serializedP
|
||||
* This function does not perform any checking if the added tag is valid.
|
||||
*/
|
||||
export function loadPositionalTag(tag: SerializedPositionalTag): PositionalTag;
|
||||
export function loadPositionalTag(tag: SerializedPositionalTag): PositionalTag {
|
||||
// Update the global arena flyout
|
||||
globalScene.arena.eventTarget.dispatchEvent(new PositionalTagAddedEvent(tag));
|
||||
|
||||
// Create the new tag
|
||||
const { tagType, ...rest } = tag;
|
||||
export function loadPositionalTag({ tagType, ...rest }: SerializedPositionalTag): PositionalTag {
|
||||
const tagClass = posTagConstructorMap[tagType];
|
||||
// @ts-expect-error - tagType always corresponds to the proper constructor for `rest`
|
||||
return new tagClass(rest);
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { loadPositionalTag } from "#data/positional-tags/load-positional-tag";
|
||||
import type { PositionalTag } from "#data/positional-tags/positional-tag";
|
||||
import type { BattlerIndex } from "#enums/battler-index";
|
||||
import type { PositionalTagType } from "#enums/positional-tag-type";
|
||||
import { PositionalTagRemovedEvent } from "#events/arena";
|
||||
|
||||
/** A manager for the {@linkcode PositionalTag}s in the arena. */
|
||||
export class PositionalTagManager {
|
||||
@ -51,16 +49,7 @@ export class PositionalTagManager {
|
||||
if (tag.shouldTrigger()) {
|
||||
tag.trigger();
|
||||
}
|
||||
this.emitRemove(tag);
|
||||
}
|
||||
this.tags = leftoverTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a {@linkcode PositionalTagRemovedEvent} whenever a tag is removed from the field.
|
||||
* @param tag - The {@linkcode PositionalTag} being removed
|
||||
*/
|
||||
private emitRemove(tag: PositionalTag): void {
|
||||
globalScene.arena.eventTarget.dispatchEvent(new PositionalTagRemovedEvent(tag.tagType, tag.targetIndex));
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,6 @@ export const ArenaEventType = {
|
||||
ARENA_TAG_ADDED: "onArenaTagAdded",
|
||||
/** Emitted when an existing {@linkcode ArenaTag} is removed */
|
||||
ARENA_TAG_REMOVED: "onArenaTagRemoved",
|
||||
|
||||
/** Emitted when a new {@linkcode PositionalTag} is added */
|
||||
POSITIONAL_TAG_ADDED: "onPositionalTagAdded",
|
||||
/** Emitted when an existing {@linkcode PositionalTag} is removed */
|
||||
POSITIONAL_TAG_REMOVED: "onPositionalTagRemoved",
|
||||
} as const;
|
||||
|
||||
export type ArenaEventType = ObjectValues<typeof ArenaEventType>;
|
||||
|
@ -1,12 +1,7 @@
|
||||
import type { SerializedPositionalTag } from "#data/positional-tags/load-positional-tag";
|
||||
// biome-ignore lint/correctness/noUnusedImports: TSDoc
|
||||
import type { PositionalTag } from "#data/positional-tags/positional-tag";
|
||||
import type { TerrainType } from "#data/terrain";
|
||||
import { ArenaEventType } from "#enums/arena-event-type";
|
||||
import type { ArenaTagSide } from "#enums/arena-tag-side";
|
||||
import type { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import type { BattlerIndex } from "#enums/battler-index";
|
||||
import type { PositionalTagType } from "#enums/positional-tag-type";
|
||||
import type { WeatherType } from "#enums/weather-type";
|
||||
|
||||
/**
|
||||
@ -128,50 +123,3 @@ export class ArenaTagRemovedEvent extends ArenaEvent {
|
||||
this.side = side;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Container class for {@linkcode ArenaEventType.POSITIONAL_TAG_ADDED} events. \
|
||||
* Emitted whenever a new {@linkcode PositionalTag} is spawned and added to the arena.
|
||||
* @eventProperty
|
||||
*/
|
||||
export class PositionalTagAddedEvent extends ArenaEvent {
|
||||
declare type: typeof ArenaEventType.POSITIONAL_TAG_ADDED;
|
||||
|
||||
/** The {@linkcode SerializedPositionalTag} being added to the arena. */
|
||||
public tag: SerializedPositionalTag;
|
||||
|
||||
/** The {@linkcode PositionalTagType} of the tag being added. */
|
||||
public tagType: PositionalTagType;
|
||||
/** The {@linkcode BattlerIndex} targeted by the newly created tag. */
|
||||
public targetIndex: BattlerIndex;
|
||||
/** The tag's current duration. */
|
||||
public duration: number;
|
||||
|
||||
constructor(tag: SerializedPositionalTag) {
|
||||
super(ArenaEventType.POSITIONAL_TAG_ADDED);
|
||||
|
||||
this.tag = tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Container class for {@linkcode ArenaEventType.POSITIONAL_TAG_REMOVED} events. \
|
||||
* Emitted whenever a currently-active {@linkcode PositionalTag} triggers (or disappears)
|
||||
* and is removed from the arena.
|
||||
* @eventProperty
|
||||
*/
|
||||
export class PositionalTagRemovedEvent extends ArenaEvent {
|
||||
declare type: typeof ArenaEventType.POSITIONAL_TAG_REMOVED;
|
||||
|
||||
/** The {@linkcode PositionalTagType} of the tag being deleted. */
|
||||
public tagType: PositionalTagType;
|
||||
/** The {@linkcode BattlerIndex} targeted by the newly removed tag. */
|
||||
public targetIndex: BattlerIndex;
|
||||
|
||||
constructor(tagType: PositionalTagType, targetIndex: BattlerIndex) {
|
||||
super(ArenaEventType.POSITIONAL_TAG_ADDED);
|
||||
|
||||
this.tagType = tagType;
|
||||
this.targetIndex = targetIndex;
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,15 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
// biome-ignore-start lint/correctness/noUnusedImports: TSDocs
|
||||
import type { ArenaTag } from "#data/arena-tag";
|
||||
import type { SerializedPositionalTag } from "#data/positional-tags/load-positional-tag";
|
||||
import type { PositionalTag } from "#data/positional-tags/positional-tag";
|
||||
import { type Terrain, TerrainType } from "#data/terrain";
|
||||
import type { Weather } from "#data/weather";
|
||||
import { ArenaEventType } from "#enums/arena-event-type";
|
||||
// biome-ignore-end lint/correctness/noUnusedImports: TSDocs
|
||||
import { ArenaTagSide } from "#enums/arena-tag-side";
|
||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import { FieldPosition } from "#enums/field-position";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import type { PositionalTagType } from "#enums/positional-tag-type";
|
||||
import { TextStyle } from "#enums/text-style";
|
||||
import { WeatherType } from "#enums/weather-type";
|
||||
import type {
|
||||
ArenaTagAddedEvent,
|
||||
ArenaTagRemovedEvent,
|
||||
PositionalTagAddedEvent,
|
||||
PositionalTagRemovedEvent,
|
||||
TerrainChangedEvent,
|
||||
WeatherChangedEvent,
|
||||
} from "#events/arena";
|
||||
import type { ArenaTagAddedEvent, ArenaTagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#events/arena";
|
||||
import { BattleSceneEventType } from "#events/battle-scene";
|
||||
import { addTextObject } from "#ui/text";
|
||||
import { TimeOfDayWidget } from "#ui/time-of-day-widget";
|
||||
@ -71,18 +58,6 @@ interface ArenaTagInfo {
|
||||
tagType?: ArenaTagType;
|
||||
}
|
||||
|
||||
/** Container for info about pending {@linkcode PositionalTag}s. */
|
||||
interface PositionalTagInfo {
|
||||
/** The localized name of the effect. */
|
||||
name: string;
|
||||
/** The {@linkcode BattlerIndex} that the effect is slated to affect. */
|
||||
targetIndex: BattlerIndex;
|
||||
/** The current duration of the effect. */
|
||||
duration: number;
|
||||
/** The tag's {@linkcode PositionalTagType}. */
|
||||
tagType: PositionalTagType;
|
||||
}
|
||||
|
||||
// #endregion interfaces
|
||||
|
||||
/**
|
||||
@ -137,19 +112,13 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
|
||||
/** Container for all {@linkcode ArenaTag}s observed by this object. */
|
||||
private arenaTags: ArenaTagInfo[] = [];
|
||||
/** Container for all {@linkcode PositionalTag}s observed by this object. */
|
||||
private positionalTags: PositionalTagInfo[] = [];
|
||||
|
||||
// Store callbacks in variables so they can be unsubscribed from when destroyed
|
||||
private readonly onNewArenaEvent = () => this.onNewArena();
|
||||
private readonly onTurnEndEvent = () => this.onTurnEnd();
|
||||
private readonly onWeatherChangedEvent = (event: WeatherChangedEvent) => this.onWeatherChanged(event);
|
||||
private readonly onTerrainChangedEvent = (event: TerrainChangedEvent) => this.onTerrainChanged(event);
|
||||
private readonly onArenaTagAddedEvent = (event: ArenaTagAddedEvent) => this.onArenaTagAdded(event);
|
||||
private readonly onArenaTagRemovedEvent = (event: ArenaTagRemovedEvent) => this.onArenaTagRemoved(event);
|
||||
private readonly onPositionalTagAddedEvent = (event: PositionalTagAddedEvent) => this.onPositionalTagAdded(event);
|
||||
// biome-ignore format: Keeps lines in 1 piece
|
||||
private readonly onPositionalTagRemovedEvent = (event: PositionalTagRemovedEvent) => this.onPositionalTagRemoved(event);
|
||||
|
||||
constructor() {
|
||||
super(globalScene, 0, 0);
|
||||
@ -267,26 +236,20 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
*/
|
||||
private onNewArena() {
|
||||
this.arenaTags = [];
|
||||
this.positionalTags = [];
|
||||
|
||||
// Subscribe to required events available on battle start
|
||||
// biome-ignore-start format: Keeps lines in 1 piece
|
||||
globalScene.arena.eventTarget.addEventListener(ArenaEventType.WEATHER_CHANGED, this.onWeatherChangedEvent);
|
||||
globalScene.arena.eventTarget.addEventListener(ArenaEventType.TERRAIN_CHANGED, this.onTerrainChangedEvent);
|
||||
globalScene.arena.eventTarget.addEventListener(ArenaEventType.ARENA_TAG_ADDED, this.onArenaTagAddedEvent);
|
||||
globalScene.arena.eventTarget.addEventListener(ArenaEventType.ARENA_TAG_REMOVED, this.onArenaTagRemovedEvent);
|
||||
globalScene.arena.eventTarget.addEventListener(ArenaEventType.POSITIONAL_TAG_ADDED, this.onPositionalTagAddedEvent);
|
||||
globalScene.arena.eventTarget.addEventListener(ArenaEventType.POSITIONAL_TAG_REMOVED, this.onPositionalTagRemovedEvent);
|
||||
// biome-ignore-end format: Keeps lines in 1 piece
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all currently present field effects and decrement their durations.
|
||||
* Iterate through all currently present tags effects and decrement their durations.
|
||||
*/
|
||||
private onTurnEnd() {
|
||||
// Remove all objects with positive max durations and whose durations have expired.
|
||||
this.arenaTags = this.arenaTags.filter(info => info.maxDuration === 0 || --info.duration >= 0);
|
||||
this.positionalTags = this.positionalTags.filter(info => --info.duration > 0);
|
||||
|
||||
this.updateFieldText();
|
||||
}
|
||||
@ -339,7 +302,6 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
*/
|
||||
private onArenaTagRemoved(event: ArenaTagRemovedEvent): void {
|
||||
const foundIndex = this.arenaTags.findIndex(info => info.tagType === event.tagType && info.side === event.side);
|
||||
console.log(this.positionalTags, event);
|
||||
|
||||
if (foundIndex > -1) {
|
||||
// If the tag was being tracked, remove it
|
||||
@ -350,42 +312,6 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
|
||||
// #endregion ArenaTags
|
||||
|
||||
// #region PositionalTags
|
||||
|
||||
/**
|
||||
* Add a recently-created {@linkcode PositionalTag} to the flyout.
|
||||
* @param event - The {@linkcode PositionalTagAddedEvent} having been emitted
|
||||
*/
|
||||
private onPositionalTagAdded(event: PositionalTagAddedEvent): void {
|
||||
const name = this.getPositionalTagDisplayName(event.tag);
|
||||
|
||||
this.positionalTags.push({
|
||||
name,
|
||||
targetIndex: event.tag.targetIndex,
|
||||
duration: event.tag.turnCount,
|
||||
tagType: event.tag.tagType,
|
||||
});
|
||||
this.updateFieldText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a recently-activated {@linkcode PositionalTag} from the flyout.
|
||||
* @param event - The {@linkcode PositionalTagRemovedEvent} having been emitted
|
||||
*/
|
||||
private onPositionalTagRemoved(event: PositionalTagRemovedEvent): void {
|
||||
const foundIndex = this.positionalTags.findIndex(
|
||||
info => info.tagType === event.tagType && info.targetIndex === event.targetIndex,
|
||||
);
|
||||
|
||||
if (foundIndex > -1) {
|
||||
// If the tag was being tracked, remove it
|
||||
this.positionalTags.splice(foundIndex, 1);
|
||||
this.updateFieldText();
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion PositionalTags
|
||||
|
||||
// #region Weather/Terrain
|
||||
|
||||
/**
|
||||
@ -458,10 +384,6 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
globalScene.arena.eventTarget.removeEventListener(ArenaEventType.TERRAIN_CHANGED, this.onTerrainChanged);
|
||||
globalScene.arena.eventTarget.removeEventListener(ArenaEventType.ARENA_TAG_ADDED, this.onArenaTagAddedEvent);
|
||||
globalScene.arena.eventTarget.removeEventListener(ArenaEventType.ARENA_TAG_REMOVED, this.onArenaTagRemovedEvent);
|
||||
// biome-ignore format: Keeps lines in 1 piece
|
||||
globalScene.arena.eventTarget.removeEventListener(ArenaEventType.POSITIONAL_TAG_ADDED, this.onPositionalTagAddedEvent);
|
||||
// biome-ignore format: Keeps lines in 1 piece
|
||||
globalScene.arena.eventTarget.removeEventListener(ArenaEventType.POSITIONAL_TAG_REMOVED, this.onPositionalTagRemovedEvent);
|
||||
|
||||
super.destroy(fromScene);
|
||||
}
|
||||
@ -489,15 +411,6 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
this.flyoutTextField.text += this.getTagText(this.terrainInfo);
|
||||
}
|
||||
|
||||
// Sort and add all positional tags
|
||||
this.positionalTags.sort(
|
||||
// Sort based on tag name, breaking ties by ascending target index.
|
||||
(infoA, infoB) => infoA.name.localeCompare(infoB.name) || infoA.targetIndex - infoB.targetIndex,
|
||||
);
|
||||
for (const tag of this.positionalTags) {
|
||||
this.getPositionalTagTextObj(tag).text += this.getPosTagText(tag);
|
||||
}
|
||||
|
||||
// Sort and update all arena tag text
|
||||
this.arenaTags.sort((infoA, infoB) => infoA.duration - infoB.duration);
|
||||
for (const tag of this.arenaTags) {
|
||||
@ -505,24 +418,6 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to retrieve the flyout text for a given {@linkcode PositionalTag}.
|
||||
* @param info - The {@linkcode PositionalTagInfo} whose text is being updated
|
||||
* @returns The text to be added to the container
|
||||
*/
|
||||
private getPosTagText(info: PositionalTagInfo): string {
|
||||
// Avoud showing slot target for single battles
|
||||
if (!globalScene.currentBattle.double) {
|
||||
return `${info.name} (${info.duration})\n`;
|
||||
}
|
||||
|
||||
const targetPos = battlerIndexToFieldPosition(info.targetIndex);
|
||||
const posText = this.localizeEffectName(FieldPosition[targetPos]);
|
||||
|
||||
// Ex: "Future Sight (Center, 2)"
|
||||
return `${info.name} (${posText}, ${info.duration})\n`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to retrieve the flyout text for a given effect's info.
|
||||
* @param info - The {@linkcode ArenaTagInfo}, {@linkcode TerrainInfo} or {@linkcode WeatherInfo} being updated
|
||||
@ -555,24 +450,6 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose which text object needs to be updated depending on the current tag's target.
|
||||
* @param info - The {@linkcode PositionalTagInfo} being displayed
|
||||
* @returns The {@linkcode Phaser.GameObjects.Text} to be updated.
|
||||
*/
|
||||
private getPositionalTagTextObj(info: PositionalTagInfo): Phaser.GameObjects.Text {
|
||||
switch (info.targetIndex) {
|
||||
case BattlerIndex.PLAYER:
|
||||
case BattlerIndex.PLAYER_2:
|
||||
return this.flyoutTextPlayer;
|
||||
case BattlerIndex.ENEMY:
|
||||
case BattlerIndex.ENEMY_2:
|
||||
return this.flyoutTextEnemy;
|
||||
case BattlerIndex.ATTACKER:
|
||||
throw new Error("BattlerIndex.ATTACKER used as tag target index for arena flyout!");
|
||||
}
|
||||
}
|
||||
|
||||
// # endregion Text display functions
|
||||
|
||||
// #region Utilities
|
||||
@ -589,32 +466,5 @@ export class ArenaFlyout extends Phaser.GameObjects.Container {
|
||||
return resultName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the localized name of a given {@linkcode PositionalTag}.
|
||||
* @param tag - The raw serialized data for the given tag
|
||||
* @returns The localized text to be displayed on-screen.
|
||||
*/
|
||||
private getPositionalTagDisplayName(tag: SerializedPositionalTag): string {
|
||||
let tagName: string;
|
||||
if ("sourceMove" in tag) {
|
||||
// Delayed attacks will use the source move's name; other effects use type directly
|
||||
tagName = MoveId[tag.sourceMove];
|
||||
} else {
|
||||
tagName = tag.tagType;
|
||||
}
|
||||
|
||||
return this.localizeEffectName(tagName);
|
||||
}
|
||||
|
||||
// #endregion Utility emthods
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a {@linkcode BattlerIndex} into a field position.
|
||||
* @param index - The {@linkcode BattlerIndex} to convert
|
||||
* @returns The resultant field position.
|
||||
*/
|
||||
function battlerIndexToFieldPosition(index: BattlerIndex): FieldPosition {
|
||||
const pos = globalScene.getField()[index]?.fieldPosition;
|
||||
return pos;
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
import type { SerializedPositionalTag } from "#data/positional-tags/load-positional-tag";
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { PositionalTagType } from "#enums/positional-tag-type";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import { mockI18next } from "#test/test-utils/test-utils";
|
||||
import type { ArenaFlyout } from "#ui/arena-flyout";
|
||||
import type i18next from "i18next";
|
||||
import Phaser from "phaser";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, type MockInstance, vi } from "vitest";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, type MockInstance } from "vitest";
|
||||
|
||||
describe("UI - Arena Flyout", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
@ -57,7 +54,6 @@ describe("UI - Arena Flyout", () => {
|
||||
|
||||
// Helper type to get around unexportedness
|
||||
type infoType = Parameters<(typeof flyout)["getTagText"]>[0];
|
||||
type posTagInfo = (typeof flyout)["positionalTags"][number];
|
||||
|
||||
describe("getTagText", () => {
|
||||
it.each<{ info: Pick<infoType, "name" | "duration" | "maxDuration">; text: string }>([
|
||||
@ -68,36 +64,4 @@ describe("UI - Arena Flyout", () => {
|
||||
expect(got).toBe(text);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getPositionalTagDisplayName", () => {
|
||||
it.each([
|
||||
{ tag: { tagType: PositionalTagType.WISH }, name: "arenaFlyout:wish" },
|
||||
{
|
||||
tag: { sourceMove: MoveId.FUTURE_SIGHT, tagType: PositionalTagType.DELAYED_ATTACK },
|
||||
name: "arenaFlyout:futureSight",
|
||||
},
|
||||
{
|
||||
tag: { sourceMove: MoveId.DOOM_DESIRE, tagType: PositionalTagType.DELAYED_ATTACK },
|
||||
name: "arenaFlyout:doomDesire",
|
||||
},
|
||||
])("should get the name of a Positional Tag", ({ tag, name }) => {
|
||||
const got = flyout["getPositionalTagDisplayName"](tag as SerializedPositionalTag);
|
||||
expect(got).toBe(name);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getPosTagText", () => {
|
||||
it.each<{ tag: Pick<posTagInfo, "duration" | "name" | "targetIndex">; output: string; double?: boolean }>([
|
||||
{ tag: { duration: 2, name: "Wish", targetIndex: BattlerIndex.PLAYER }, output: "Wish (2)" },
|
||||
{
|
||||
tag: { duration: 1, name: "Future Sight", targetIndex: BattlerIndex.ENEMY_2 },
|
||||
double: true,
|
||||
output: "Future Sight (arenaFlyout:right, 1)",
|
||||
},
|
||||
])("should produce the correct text", ({ tag, output, double = false }) => {
|
||||
vi.spyOn(game.scene.currentBattle, "double", "get").mockReturnValue(double);
|
||||
const text = flyout["getPosTagText"](tag as posTagInfo);
|
||||
expect(text).toBe(output + "\n");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user