Merge pull request #1 from arnochauveau/refactor-ts-exercise

Refactor ts exercise
This commit is contained in:
Arno Chauveau 2025-07-24 16:13:56 +02:00 committed by GitHub
commit 1b80c27e67
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 2018 additions and 289 deletions

View File

@ -1,11 +0,0 @@
"use strict";
module.exports = {
require: [
"ts-node/register",
"tsconfig-paths/register",
"source-map-support/register"
],
recursive: true,
spec: "test/mocha/*.spec.ts"
}

View File

@ -1,17 +0,0 @@
module.exports = {
extension: [
".ts"
],
exclude: [
"**/*.d.ts",
"test/**",
"/*.js"
],
require: [
"ts-node/register"
],
reporter: [
"html",
"text"
]
}

3
TypeScript/app/config.ts Normal file
View File

@ -0,0 +1,3 @@
export const config = {
maxQuality: 50,
};

View File

@ -0,0 +1,38 @@
const getUpdateBehaviorMock = jest.fn((item: Item) => new MockBehavior(item));
const updateMock = jest.fn((item: Item) => item);
jest.mock("@app/update-behaviors", () => ({
getUpdateBehaviorFor: getUpdateBehaviorMock,
}));
import { GildedRose } from "@app/gilded-rose";
import { Item } from "@app/item";
import { IUpdateBehavior } from "@app/update-behaviors";
export class MockBehavior implements IUpdateBehavior {
constructor(public item: Item) {}
update() {
return updateMock(this.item);
}
}
describe("Gilded Rose", () => {
it("should have an empty array as items when no constructor parameter is provided", () => {
const gildedRose = new GildedRose();
expect(gildedRose.items).toEqual([]);
});
it("should call the behavior resolver and update function for each item", () => {
const item1 = new Item("item 1", 0, 0);
const item2 = new Item("item 2", 0, 0);
const gildedRose = new GildedRose([item1, item2]);
gildedRose.updateQuality();
expect(getUpdateBehaviorMock).toHaveBeenCalledWith(item1);
expect(getUpdateBehaviorMock).toHaveBeenCalledWith(item2);
expect(updateMock).toHaveBeenCalledWith(item1);
expect(updateMock).toHaveBeenCalledWith(item2);
});
});

View File

@ -1,16 +1,9 @@
export class Item {
name: string;
sellIn: number;
quality: number;
constructor(name, sellIn, quality) {
this.name = name;
this.sellIn = sellIn;
this.quality = quality;
}
}
import { Item } from "@app/item";
import { getUpdateBehaviorFor } from "@app/update-behaviors";
export class GildedRose {
// also can't edit this because of the kata rules.
// But I prefer typing this as : Item[]
items: Array<Item>;
constructor(items = [] as Array<Item>) {
@ -18,52 +11,8 @@ export class GildedRose {
}
updateQuality() {
for (let i = 0; i < this.items.length; i++) {
if (this.items[i].name != 'Aged Brie' && this.items[i].name != 'Backstage passes to a TAFKAL80ETC concert') {
if (this.items[i].quality > 0) {
if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') {
this.items[i].quality = this.items[i].quality - 1
}
}
} else {
if (this.items[i].quality < 50) {
this.items[i].quality = this.items[i].quality + 1
if (this.items[i].name == 'Backstage passes to a TAFKAL80ETC concert') {
if (this.items[i].sellIn < 11) {
if (this.items[i].quality < 50) {
this.items[i].quality = this.items[i].quality + 1
}
}
if (this.items[i].sellIn < 6) {
if (this.items[i].quality < 50) {
this.items[i].quality = this.items[i].quality + 1
}
}
}
}
}
if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') {
this.items[i].sellIn = this.items[i].sellIn - 1;
}
if (this.items[i].sellIn < 0) {
if (this.items[i].name != 'Aged Brie') {
if (this.items[i].name != 'Backstage passes to a TAFKAL80ETC concert') {
if (this.items[i].quality > 0) {
if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') {
this.items[i].quality = this.items[i].quality - 1
}
}
} else {
this.items[i].quality = this.items[i].quality - this.items[i].quality
}
} else {
if (this.items[i].quality < 50) {
this.items[i].quality = this.items[i].quality + 1
}
}
}
}
return this.items;
return this.items.map((item) => {
return getUpdateBehaviorFor(item).update();
});
}
}

18
TypeScript/app/item.ts Normal file
View File

@ -0,0 +1,18 @@
export class Item {
name: string;
sellIn: number;
quality: number;
// can't edit this constructor because of the kata rules.
// but I would change the constructor to take a javaScript object.
// It makes the consumer code more readable.
// e.g. new Item({ name: "standard item", sellIn: 0, quality: 2 })
// instead of new Item("standard item", 0, 2)
// I would also type the parameters, because now they are implicitly any.
constructor(name, sellIn, quality) {
this.name = name;
this.sellIn = sellIn;
this.quality = quality;
}
}

View File

@ -0,0 +1,40 @@
import { Item } from "@app/item";
import { getUpdateBehaviorFor } from "./behavior-resolver";
import { AgedBrieBehavior } from "./implementations/aged-brie/aged-brie-behavior";
import { DefaultBehavior } from "./implementations/default/default-behavior";
import { BackstagePassBehavior } from "./implementations/backstage-pass/backstage-pass-behavior";
import { LegendaryItemBehavior } from "./implementations/legendary-item/legendary-item-behavior";
import { ConjuredItemBehavior } from "./implementations/conjured-item/conjured-item-behavior";
describe("Behavior resolver", () => {
it("should correctly resolve Aged Brie", () => {
expect(getUpdateBehaviorFor(new Item("Aged Brie", 0, 0))).toBeInstanceOf(
AgedBrieBehavior
);
});
it("should correctly resolve Backstage Passes", () => {
expect(
getUpdateBehaviorFor(
new Item("Backstage passes to a TAFKAL80ETC concert", 0, 0)
)
).toBeInstanceOf(BackstagePassBehavior);
});
it("should correctly resolve Legendary Items", () => {
expect(
getUpdateBehaviorFor(new Item("Sulfuras, Hand of Ragnaros", 0, 0))
).toBeInstanceOf(LegendaryItemBehavior);
});
it("should correctly resolve Conjured Items", () => {
expect(
getUpdateBehaviorFor(new Item("Conjured Mana Cake", 0, 0))
).toBeInstanceOf(ConjuredItemBehavior);
});
it("should correctly resolve the rest to Legacy behavior", () => {
expect(
getUpdateBehaviorFor(new Item("some other item", 0, 0))
).toBeInstanceOf(DefaultBehavior);
});
});

View File

@ -0,0 +1,22 @@
import { Item } from "@app/item";
import { IUpdateBehavior } from "./update-behavior.interface";
import { DefaultBehavior } from "./implementations/default/default-behavior";
import { AgedBrieBehavior } from "./implementations/aged-brie/aged-brie-behavior";
import { BackstagePassBehavior } from "./implementations/backstage-pass/backstage-pass-behavior";
import { LegendaryItemBehavior } from "./implementations/legendary-item/legendary-item-behavior";
import { ConjuredItemBehavior } from "./implementations/conjured-item/conjured-item-behavior";
export function getUpdateBehaviorFor(item: Item): IUpdateBehavior {
switch (item.name) {
case "Aged Brie":
return new AgedBrieBehavior(item);
case "Backstage passes to a TAFKAL80ETC concert":
return new BackstagePassBehavior(item);
case "Sulfuras, Hand of Ragnaros":
return new LegendaryItemBehavior(item);
case "Conjured Mana Cake":
return new ConjuredItemBehavior(item);
default:
return new DefaultBehavior(item);
}
}

View File

@ -0,0 +1,40 @@
import { Item } from "@app/item";
import { AgedBrieBehavior } from "./aged-brie-behavior";
describe("AgedBrie Behavior", () => {
it("should increase quality of Aged Brie as it gets older", () => {
const behavior = new AgedBrieBehavior(new Item("Aged Brie", 1, 1));
const result = behavior.update();
expect(result).toMatchObject({
name: "Aged Brie",
sellIn: 0,
quality: 2,
});
});
it("should increase quality of Aged Brie twice as fast after sell in date", () => {
const behavior = new AgedBrieBehavior(new Item("Aged Brie", 0, 1));
const result = behavior.update();
expect(result).toMatchObject({
name: "Aged Brie",
sellIn: -1,
quality: 3,
});
});
it("should never increase quality of Aged Brie over 50", () => {
const behavior = new AgedBrieBehavior(new Item("Aged Brie", 0, 50));
const result = behavior.update();
expect(result).toMatchObject({
name: "Aged Brie",
sellIn: -1,
quality: 50,
});
});
});

View File

@ -0,0 +1,22 @@
import { config } from "@app/config";
import { Item } from "@app/item";
import { IUpdateBehavior } from "@app/update-behaviors";
export class AgedBrieBehavior implements IUpdateBehavior {
constructor(private item: Item) {}
update(): Item {
const isPastSellInDay = this.item.sellIn <= 0;
const amountToAdd = isPastSellInDay ? 2 : 1;
this.item.quality = Math.min(
config.maxQuality,
this.item.quality + amountToAdd
);
this.item.sellIn -= 1;
return this.item;
}
}

View File

@ -0,0 +1,74 @@
import { Item } from "@app/item";
import { BackstagePassBehavior } from "./backstage-pass-behavior";
describe("Backstage Pass Behavior", () => {
it("should increase quality of Backstage passes by 1 if sell in date is more than 10 days away", () => {
const behavior = new BackstagePassBehavior(
new Item("Backstage passes to a TAFKAL80ETC concert", 11, 20)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Backstage passes to a TAFKAL80ETC concert",
sellIn: 10,
quality: 21,
});
});
it("should increase quality of Backstage passes by 2 if sell in date is less than 10 days away but more than 5", () => {
const behavior = new BackstagePassBehavior(
new Item("Backstage passes to a TAFKAL80ETC concert", 9, 20)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Backstage passes to a TAFKAL80ETC concert",
sellIn: 8,
quality: 22,
});
});
it("should increase quality of Backstage passes by 3 if sell in date is less than 5 days away", () => {
const behavior = new BackstagePassBehavior(
new Item("Backstage passes to a TAFKAL80ETC concert", 4, 20)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Backstage passes to a TAFKAL80ETC concert",
sellIn: 3,
quality: 23,
});
});
it("should drop quality of Backstage passes to 0 after sell in date", () => {
const behavior = new BackstagePassBehavior(
new Item("Backstage passes to a TAFKAL80ETC concert", 0, 20)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Backstage passes to a TAFKAL80ETC concert",
sellIn: -1,
quality: 0,
});
});
it("should not increase over 50", () => {
const behavior = new BackstagePassBehavior(
new Item("Backstage passes to a TAFKAL80ETC concert", 4, 50)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Backstage passes to a TAFKAL80ETC concert",
sellIn: 3,
quality: 50,
});
});
});

View File

@ -0,0 +1,30 @@
import { config } from "@app/config";
import { Item } from "@app/item";
import { IUpdateBehavior } from "@app/update-behaviors";
export class BackstagePassBehavior implements IUpdateBehavior {
constructor(private item: Item) {}
update(): Item {
const sellIn = this.item.sellIn;
const amountToIncrease = this.#getAmountToIncrease(sellIn);
this.item.quality = Math.min(
this.item.quality + amountToIncrease,
config.maxQuality
);
if (sellIn <= 0) {
this.item.quality = 0;
}
this.item.sellIn -= 1;
return this.item;
}
#getAmountToIncrease(sellIn: number): number {
if (sellIn <= 5) return 3;
if (sellIn <= 10) return 2;
return 1;
}
}

View File

@ -0,0 +1,59 @@
import { Item } from "@app/item";
import { ConjuredItemBehavior } from "./conjured-item-behavior";
describe("Conjured Item Behavior", () => {
it("should degrade quality with 2 and sellIn with 1 when sellIn is over 0", () => {
const behavior = new ConjuredItemBehavior(
new Item("Conjured Mana Cake", 1, 4)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Conjured Mana Cake",
sellIn: 0,
quality: 2,
});
});
it("should degrade quality with 4 and sellin with 1 when sellIn is equal to zero", () => {
const behavior = new ConjuredItemBehavior(
new Item("Conjured Mana Cake", 0, 5)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Conjured Mana Cake",
sellIn: -1,
quality: 1,
});
});
it("should degrade quality with 4 and sellin with 1 when sellIn is under zero", () => {
const behavior = new ConjuredItemBehavior(
new Item("Conjured Mana Cake", -1, 5)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Conjured Mana Cake",
sellIn: -2,
quality: 1,
});
});
it("shouldn't degrade quality under 0", () => {
const behavior = new ConjuredItemBehavior(
new Item("Conjured Mana Cake", 1, 1)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Conjured Mana Cake",
sellIn: 0,
quality: 0,
});
});
});

View File

@ -0,0 +1,16 @@
import { Item } from "@app/item";
import { IUpdateBehavior } from "@app/update-behaviors/update-behavior.interface";
export class ConjuredItemBehavior implements IUpdateBehavior {
constructor(private item: Item) {}
update(): Item {
const amountToSubtract = this.item.sellIn <= 0 ? 4 : 2;
this.item.quality = Math.max(this.item.quality - amountToSubtract, 0);
this.item.sellIn -= 1;
return this.item;
}
}

View File

@ -0,0 +1,40 @@
import { Item } from "@app/item";
import { DefaultBehavior } from "./default-behavior";
describe("Default Behavior", () => {
it("should degrade sell inn and quality each day", () => {
const behavior = new DefaultBehavior(new Item("standard item", 1, 1));
const result = behavior.update();
expect(result).toMatchObject({
name: "standard item",
sellIn: 0,
quality: 0,
});
});
it("should degrade quality twice as fast after sell in date", () => {
const behavior = new DefaultBehavior(new Item("standard item", 0, 2));
const result = behavior.update();
expect(result).toMatchObject({
name: "standard item",
sellIn: -1,
quality: 0,
});
});
it("should not degrade quality below 0", () => {
const behavior = new DefaultBehavior(new Item("standard item", 1, 0));
const result = behavior.update();
expect(result).toMatchObject({
name: "standard item",
sellIn: 0,
quality: 0,
});
});
});

View File

@ -0,0 +1,15 @@
import { Item } from "@app/item";
import { IUpdateBehavior } from "../../update-behavior.interface";
export class DefaultBehavior implements IUpdateBehavior {
constructor(private item: Item) {}
update(): Item {
const amountToSubtract = this.item.sellIn <= 0 ? 2 : 1;
this.item.quality = Math.max(this.item.quality - amountToSubtract, 0);
this.item.sellIn -= 1;
return this.item;
}
}

View File

@ -0,0 +1,13 @@
import { config } from "@app/config";
import { Item } from "@app/item";
import { IUpdateBehavior } from "@app/update-behaviors/update-behavior.interface";
export class LegendaryItemBehavior implements IUpdateBehavior {
constructor(public item: Item) {}
update(): Item {
if (this.item.quality !== 80) {
throw new Error("A Legendary Item cannot have a quality other than 80");
}
return this.item;
}
}

View File

@ -0,0 +1,28 @@
import { Item } from "@app/item";
import { LegendaryItemBehavior } from "./legendary-item-behavior";
describe("Legendary Item Behavior", () => {
it("should keep items of quality 80 the same", () => {
const behavior = new LegendaryItemBehavior(
new Item("Sulfuras, Hand of Ragnaros", 0, 80)
);
const result = behavior.update();
expect(result).toMatchObject({
name: "Sulfuras, Hand of Ragnaros",
sellIn: 0,
quality: 80,
});
});
it("should throw an error when a legendary item doesn't have a quality of 80", () => {
const behavior = new LegendaryItemBehavior(
new Item("Sulfuras, Hand of Ragnaros", 0, 5)
);
expect(() => behavior.update()).toThrow(
"A Legendary Item cannot have a quality other than 80"
);
});
});

View File

@ -0,0 +1,2 @@
export * from "./update-behavior.interface";
export * from "./behavior-resolver";

View File

@ -0,0 +1,5 @@
import { Item } from "@app/item";
export interface IUpdateBehavior {
update: () => Item;
}

View File

@ -1,13 +1,15 @@
import { pathsToModuleNameMapper } from "ts-jest";
import { compilerOptions } from './tsconfig.json'
import { pathsToModuleNameMapper } from "ts-jest";
import { compilerOptions } from "./tsconfig.json";
export default {
roots: ['<rootDir>/app', '<rootDir>/test/jest'],
roots: ["<rootDir>/app", "<rootDir>/snapshot-tests"],
collectCoverage: true,
coverageDirectory: 'coverage',
coverageProvider: 'v8',
coverageDirectory: "coverage",
coverageProvider: "v8",
transform: {
'^.+\\.tsx?$': 'ts-jest',
"^.+\\.tsx?$": "ts-jest",
},
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' } ),
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
prefix: "<rootDir>/",
}),
};

View File

@ -3,33 +3,23 @@
"version": "1.0.0",
"description": "Gilded Rose kata in TypeScript",
"scripts": {
"precompile": "rimraf app/**/*.js test/**/*.js",
"precompile": "rimraf app/**/*.js snapshot-tests/**/*.js",
"compile": "tsc",
"pretest": "rimraf app/**/*.js test/**/*.js",
"test:jest": "jest",
"test:jest:watch": "jest --watchAll",
"test:mocha": "nyc mocha",
"test:vitest": "vitest --coverage"
"pretest": "rimraf app/**/*.js snapshot-tests/**/*.js",
"test": "jest",
"test:watch": "jest --watchAll"
},
"license": "MIT",
"private": true,
"devDependencies": {
"@types/chai": "^4.2.22",
"@types/jest": "^29.4.0",
"@types/mocha": "^10.0.1",
"@types/node": "^18.14.0",
"@vitest/coverage-istanbul": "^0.28.5",
"chai": "^4.3.4",
"jest": "^29.4.3",
"mocha": "^10.2.0",
"nyc": "~15.1.0",
"rimraf": "^4.1.2",
"source-map-support": "^0.5.20",
"ts-jest": "^29.0.5",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.2",
"typescript": "^4.4.4",
"vite-tsconfig-paths": "^4.0.5",
"vitest": "^0.28.5"
"typescript": "^4.4.4"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
import { GildedRose } from "@app/gilded-rose";
import { Item } from "@app/item";
describe("Gilded Rose Approval", () => {
it("should match the snapshot for thirty Days", () => {
const items = [
new Item("+5 Dexterity Vest", 10, 20), //
new Item("Aged Brie", 2, 0), //
new Item("Elixir of the Mongoose", 5, 7), //
new Item("Sulfuras, Hand of Ragnaros", 0, 80), //
new Item("Sulfuras, Hand of Ragnaros", -1, 80),
new Item("Backstage passes to a TAFKAL80ETC concert", 15, 20),
new Item("Backstage passes to a TAFKAL80ETC concert", 10, 49),
new Item("Backstage passes to a TAFKAL80ETC concert", 5, 49),
// this conjured item does not work properly yet
new Item("Conjured Mana Cake", 3, 6),
];
const gildedRose = new GildedRose(items);
const days = 30;
for (let i = 0; i < days; i++) {
const updatedItems = gildedRose.updateQuality();
expect(updatedItems).toMatchSnapshot();
}
});
});

View File

@ -1,34 +0,0 @@
import { Item, GildedRose } from '../app/gilded-rose';
console.log("OMGHAI!")
const items = [
new Item("+5 Dexterity Vest", 10, 20), //
new Item("Aged Brie", 2, 0), //
new Item("Elixir of the Mongoose", 5, 7), //
new Item("Sulfuras, Hand of Ragnaros", 0, 80), //
new Item("Sulfuras, Hand of Ragnaros", -1, 80),
new Item("Backstage passes to a TAFKAL80ETC concert", 15, 20),
new Item("Backstage passes to a TAFKAL80ETC concert", 10, 49),
new Item("Backstage passes to a TAFKAL80ETC concert", 5, 49),
// this conjured item does not work properly yet
new Item("Conjured Mana Cake", 3, 6)];
const gildedRose = new GildedRose(items);
let days: number = 2;
if (process.argv.length > 2) {
days = +process.argv[2];
}
for (let i = 0; i < days + 1; i++) {
console.log("-------- day " + i + " --------");
console.log("name, sellIn, quality");
items.forEach(element => {
console.log(element.name + ', ' + element.sellIn + ', ' + element.quality);
});
console.log();
gildedRose.updateQuality();
}

View File

@ -1,54 +0,0 @@
import { Item, GildedRose } from '@/gilded-rose';
/**
* This unit test uses [Jest Snapshot](https://goo.gl/fbAQLP).
*
* There are two test cases here with different styles:
* <li>"foo" is more similar to the unit test from the 'Java' version
* <li>"thirtyDays" is more similar to the TextTest from the 'Java' version
*
* I suggest choosing one style to develop and deleting the other.
*/
describe('Gilded Rose Approval', () => {
let gameConsoleOutput: string;
let originalConsoleLog: (message: any) => void;
let originalProcessArgv: string[]
function gameConsoleLog(msg: string) {
if (msg) {
gameConsoleOutput += msg;
}
gameConsoleOutput += "\n";
}
beforeEach(() => {
// prepare capturing console.log to our own gameConsoleLog.
gameConsoleOutput = "";
originalConsoleLog = console.log;
console.log = gameConsoleLog;
originalProcessArgv = process.argv;
});
afterEach(() => {
// reset original console.log
console.log = originalConsoleLog;
process.argv = originalProcessArgv;
});
it('should foo', () => {
const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
const items = gildedRose.updateQuality();
expect(items).toMatchSnapshot();
});
it('should thirtyDays', () => {
process.argv = ["<node>", "<script", "30"];
require('../golden-master-text-test.ts');
expect(gameConsoleOutput).toMatchSnapshot();
});
});

View File

@ -1,9 +0,0 @@
import { Item, GildedRose } from '@/gilded-rose';
describe('Gilded Rose', () => {
it('should foo', () => {
const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
const items = gildedRose.updateQuality();
expect(items[0].name).toBe('fixme');
});
});

View File

@ -1,10 +0,0 @@
import { expect } from 'chai';
import { Item, GildedRose } from '@/gilded-rose';
describe('Gilded Rose', () => {
it('should foo', () => {
const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
const items = gildedRose.updateQuality();
expect(items[0].name).to.equal('fixme');
});
});

View File

@ -1,30 +0,0 @@
import { execSync } from 'node:child_process';
import { Item, GildedRose } from '@/gilded-rose';
/**
* This test uses Vitest Snapshot, similar to [Jest Snapshot](https://goo.gl/fbAQLP).
*
* There are two test cases here with different styles:
* <li>"foo" is more similar to the unit test from the 'Java' version
* <li>"thirtyDays" is more similar to the TextTest from the 'Java' version
*
* I suggest choosing one style to develop and deleting the other.
*/
describe('Gilded Rose Approval', () => {
it('should foo', () => {
const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
const items = gildedRose.updateQuality();
expect(items).toMatchSnapshot();
});
it('should thirtyDays', () => {
const consoleOutput = execSync(
'ts-node test/golden-master-text-test.ts 30',
{ encoding: 'utf-8' }
);
expect(consoleOutput).toMatchSnapshot();
});
});

View File

@ -1,9 +0,0 @@
import { Item, GildedRose } from '@/gilded-rose';
describe('Gilded Rose', () => {
it('should foo', () => {
const gildedRose = new GildedRose([new Item('foo', 0, 0)]);
const items = gildedRose.updateQuality();
expect(items[0].name).toBe('fixme');
});
});

View File

@ -1,14 +0,0 @@
#!/usr/bin/env python
"""
This script uses npx to execute the TextTest Fixture for TypeScript.
It is designed to be used by TextTest and specified in the file 'texttests/config.gr' in this repo.
It is more convenient for TextTest to use since npx needs
several arguments in addition to the one the TextTest fixture needs.
"""
import os
import subprocess
import sys
args = " ".join(sys.argv[1:])
TEXTTEST_HOME = os.environ.get("TEXTTEST_HOME", os.getcwd())
subprocess.run(f"npx ts-node {TEXTTEST_HOME}/TypeScript/test/golden-master-text-test.ts {args}", shell=True)

View File

@ -1,7 +1,7 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"target": "es2022",
"strict": true,
"noImplicitAny": false,
"sourceMap": true,
@ -9,12 +9,8 @@
"resolveJsonModule": true,
"esModuleInterop": true,
"paths": {
"@/*": [
"app/*"
]
"@app/*": ["app/*"]
}
},
"exclude": [
"node_modules"
]
"exclude": ["node_modules"]
}

View File

@ -1,14 +0,0 @@
import {defineConfig} from 'vitest/config';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [tsconfigPaths()],
test: {
globals: true,
include: ['test/vitest/**/*.{spec,test}.{js,ts}'],
coverage: {
provider: 'istanbul',
reporter: ['text', 'html']
}
},
});