Skip to content

Commit 6d1c68c

Browse files
committed
Convert pre-modules exercises to stdout-based testing
1 parent b6d3a5e commit 6d1c68c

File tree

24 files changed

+459
-209
lines changed

24 files changed

+459
-209
lines changed

exercises/01.classes/01.problem.class-basics/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,26 @@
1818
// cart.addItem(laptop)
1919
// cart.addItem(mouse)
2020
// console.log(cart.getTotal())
21+
22+
// 🐨 When you're done, uncomment this:
23+
// const sampleCart = new ShoppingCart()
24+
// const sampleLaptop = new Product('Laptop', 999.99)
25+
// const sampleMouse = new Product('Mouse', 29.99)
26+
// sampleCart.addItem(sampleLaptop)
27+
// sampleCart.addItem(sampleMouse)
28+
// console.log(
29+
// 'Results JSON:',
30+
// JSON.stringify({
31+
// product: {
32+
// name: sampleLaptop.name,
33+
// price: sampleLaptop.price,
34+
// description: sampleLaptop.getDescription(),
35+
// },
36+
// cart: {
37+
// itemsCount: sampleCart.items.length,
38+
// firstItemName: sampleCart.items[0]?.name,
39+
// secondItemName: sampleCart.items[1]?.name,
40+
// total: sampleCart.getTotal(),
41+
// },
42+
// }),
43+
// )

exercises/01.classes/01.solution.class-basics/index.test.ts

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,72 @@
11
import assert from 'node:assert/strict'
2+
import { execSync } from 'node:child_process'
23
import { test } from 'node:test'
3-
// @ts-ignore - these won't appear in the problem file
4-
import { Product, ShoppingCart } from './index.ts'
4+
5+
const output = execSync('npm start --silent', { encoding: 'utf8' })
6+
const jsonLine = output
7+
.split('\n')
8+
.find((line) => line.startsWith('Results JSON:'))
9+
assert.ok(jsonLine, '🚨 Missing "Results JSON:" output line')
10+
const { product, cart, emptyCart } = JSON.parse(
11+
jsonLine.replace('Results JSON:', '').trim(),
12+
)
513

614
await test('Product class should create instances with name and price', () => {
7-
const laptop = new Product('Laptop', 999.99)
815
assert.strictEqual(
9-
laptop.name,
16+
product.name,
1017
'Laptop',
1118
'🚨 Product.name should be "Laptop" - check your class property definition',
1219
)
1320
assert.strictEqual(
14-
laptop.price,
21+
product.price,
1522
999.99,
1623
'🚨 Product.price should be 999.99 - check your class property definition',
1724
)
1825
})
1926

2027
await test('Product getDescription should return formatted string', () => {
21-
const mouse = new Product('Mouse', 29.99)
22-
const description = mouse.getDescription()
2328
assert.strictEqual(
24-
description,
25-
'Product: Mouse - $29.99',
29+
product.description,
30+
'Product: Laptop - $999.99',
2631
'🚨 getDescription() should return "Product: Mouse - $29.99" - check your method implementation and formatting',
2732
)
2833
})
2934

3035
await test('ShoppingCart should initialize with empty items array', () => {
31-
const cart = new ShoppingCart()
32-
assert.deepStrictEqual(
33-
cart.items,
34-
[],
35-
'🚨 ShoppingCart.items should be an empty array - check your class property initialization',
36-
)
3736
assert.strictEqual(
38-
cart.items.length,
37+
emptyCart.itemsCount,
3938
0,
4039
'🚨 ShoppingCart.items.length should be 0 - check your class property initialization',
4140
)
4241
})
4342

4443
await test('ShoppingCart addItem should add products to cart', () => {
45-
const cart = new ShoppingCart()
46-
const laptop = new Product('Laptop', 999.99)
47-
const mouse = new Product('Mouse', 29.99)
48-
49-
cart.addItem(laptop)
5044
assert.strictEqual(
51-
cart.items.length,
45+
cart.itemsAfterFirstAdd,
5246
1,
5347
'🚨 After adding one item, items.length should be 1 - check your addItem method implementation',
5448
)
5549
assert.strictEqual(
56-
cart.items[0],
57-
laptop,
50+
cart.firstItemName,
51+
'Laptop',
5852
'🚨 items[0] should be the laptop product - check your addItem method implementation',
5953
)
6054

61-
cart.addItem(mouse)
6255
assert.strictEqual(
63-
cart.items.length,
56+
cart.itemsCount,
6457
2,
6558
'🚨 After adding two items, items.length should be 2 - check your addItem method implementation',
6659
)
6760
assert.strictEqual(
68-
cart.items[1],
69-
mouse,
61+
cart.secondItemName,
62+
'Mouse',
7063
'🚨 items[1] should be the mouse product - check your addItem method implementation',
7164
)
7265
})
7366

7467
await test('ShoppingCart getTotal should calculate sum of all item prices', () => {
75-
const cart = new ShoppingCart()
76-
const laptop = new Product('Laptop', 999.99)
77-
const mouse = new Product('Mouse', 29.99)
78-
79-
cart.addItem(laptop)
80-
cart.addItem(mouse)
81-
82-
const total = cart.getTotal()
8368
assert.strictEqual(
84-
total,
69+
cart.total,
8570
1029.98,
8671
'🚨 getTotal() should return 1029.98 (sum of 999.99 + 29.99) - check your method implementation and price calculation',
8772
)

exercises/01.classes/01.solution.class-basics/index.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Creating Classes
22

3-
export class Product {
3+
class Product {
44
name: string
55
price: number
66

@@ -14,7 +14,7 @@ export class Product {
1414
}
1515
}
1616

17-
export class ShoppingCart {
17+
class ShoppingCart {
1818
items: Array<Product>
1919

2020
constructor() {
@@ -40,3 +40,32 @@ const cart = new ShoppingCart()
4040
cart.addItem(laptop)
4141
cart.addItem(mouse)
4242
console.log(`Cart total: $${cart.getTotal()}`)
43+
44+
const sampleCart = new ShoppingCart()
45+
const emptyCart = new ShoppingCart()
46+
const sampleLaptop = new Product('Laptop', 999.99)
47+
const sampleMouse = new Product('Mouse', 29.99)
48+
sampleCart.addItem(sampleLaptop)
49+
const afterFirstAddCount = sampleCart.items.length
50+
sampleCart.addItem(sampleMouse)
51+
52+
console.log(
53+
'Results JSON:',
54+
JSON.stringify({
55+
product: {
56+
name: sampleLaptop.name,
57+
price: sampleLaptop.price,
58+
description: sampleLaptop.getDescription(),
59+
},
60+
cart: {
61+
itemsCount: sampleCart.items.length,
62+
itemsAfterFirstAdd: afterFirstAddCount,
63+
firstItemName: sampleCart.items[0]?.name,
64+
secondItemName: sampleCart.items[1]?.name,
65+
total: sampleCart.getTotal(),
66+
},
67+
emptyCart: {
68+
itemsCount: emptyCart.items.length,
69+
},
70+
}),
71+
)

exercises/01.classes/02.problem.constructors/index.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// - name: string
55
// - email: string
66
// - role: string (default: 'user')
7-
// Use constructor parameter shorthand!
7+
// Initialize fields in the constructor
88

99
// 🐨 Create a BankAccount class with:
1010
// - accountNumber: string
@@ -25,3 +25,27 @@
2525
// account.deposit(100)
2626
// const config = new Config()
2727
// const customConfig = new Config('example.com', 8080, true)
28+
29+
// 🐨 When you're done, uncomment this:
30+
// const sampleAccount = new BankAccount('12345')
31+
// sampleAccount.deposit(100)
32+
// sampleAccount.deposit(50)
33+
// console.log(
34+
// 'Results JSON:',
35+
// JSON.stringify({
36+
// user: { name: user.name, email: user.email, role: user.role },
37+
// admin: { name: admin.name, email: admin.email, role: admin.role },
38+
// account: {
39+
// accountNumber: sampleAccount.accountNumber,
40+
// initialBalance: 0,
41+
// balanceAfterFirstDeposit: 100,
42+
// balanceAfterSecondDeposit: 150,
43+
// },
44+
// config: { host: config.host, port: config.port, debug: config.debug },
45+
// customConfig: {
46+
// host: customConfig.host,
47+
// port: customConfig.port,
48+
// debug: customConfig.debug,
49+
// },
50+
// }),
51+
// )

exercises/01.classes/02.solution.constructors/index.test.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import assert from 'node:assert/strict'
2+
import { execSync } from 'node:child_process'
23
import { test } from 'node:test'
3-
import { User, BankAccount, Config } from './index.ts'
4+
5+
const output = execSync('npm start --silent', { encoding: 'utf8' })
6+
const jsonLine = output
7+
.split('\n')
8+
.find((line) => line.startsWith('Results JSON:'))
9+
assert.ok(jsonLine, '🚨 Missing "Results JSON:" output line')
10+
const { user, admin, account, config, customConfig } = JSON.parse(
11+
jsonLine.replace('Results JSON:', '').trim(),
12+
)
413

514
await test('User constructor should set name, email, and default role', () => {
6-
const user = new User('Alice', '[email protected]')
715
assert.strictEqual(
816
user.name,
917
'Alice',
@@ -22,7 +30,6 @@ await test('User constructor should set name, email, and default role', () => {
2230
})
2331

2432
await test('User constructor should accept custom role', () => {
25-
const admin = new User('Bob', '[email protected]', 'admin')
2633
assert.strictEqual(
2734
admin.name,
2835
'Bob',
@@ -41,37 +48,32 @@ await test('User constructor should accept custom role', () => {
4148
})
4249

4350
await test('BankAccount constructor should set accountNumber and default balance', () => {
44-
const account = new BankAccount('12345')
4551
assert.strictEqual(
4652
account.accountNumber,
4753
'12345',
4854
'🚨 BankAccount.accountNumber should be "12345" - check your constructor parameter assignment',
4955
)
5056
assert.strictEqual(
51-
account.getBalance(),
57+
account.initialBalance,
5258
0,
5359
'🚨 BankAccount.getBalance() should return 0 initially - check your constructor initialization',
5460
)
5561
})
5662

5763
await test('BankAccount deposit should increase balance', () => {
58-
const account = new BankAccount('12345')
59-
account.deposit(100)
6064
assert.strictEqual(
61-
account.getBalance(),
65+
account.balanceAfterFirstDeposit,
6266
100,
6367
'🚨 After depositing 100, getBalance() should return 100 - check your deposit method implementation',
6468
)
65-
account.deposit(50)
6669
assert.strictEqual(
67-
account.getBalance(),
70+
account.balanceAfterSecondDeposit,
6871
150,
6972
'🚨 After depositing another 50, getBalance() should return 150 - check your deposit method accumulates correctly',
7073
)
7174
})
7275

7376
await test('Config constructor should use default values', () => {
74-
const config = new Config()
7577
assert.strictEqual(
7678
config.host,
7779
'localhost',
@@ -90,7 +92,6 @@ await test('Config constructor should use default values', () => {
9092
})
9193

9294
await test('Config constructor should accept custom values', () => {
93-
const customConfig = new Config('example.com', 8080, true)
9495
assert.strictEqual(
9596
customConfig.host,
9697
'example.com',
Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
// Constructor Patterns
22

3-
export class User {
4-
constructor(
5-
public name: string,
6-
public email: string,
7-
public role: string = 'user',
8-
) {}
3+
class User {
4+
name: string
5+
email: string
6+
role: string
7+
8+
constructor(name: string, email: string, role: string = 'user') {
9+
this.name = name
10+
this.email = email
11+
this.role = role
12+
}
913
}
1014

11-
export class BankAccount {
15+
class BankAccount {
1216
#balance: number = 0
17+
accountNumber: string
1318

14-
constructor(public accountNumber: string) {}
19+
constructor(accountNumber: string) {
20+
this.accountNumber = accountNumber
21+
}
1522

1623
deposit(amount: number): void {
1724
this.#balance += amount
@@ -22,12 +29,20 @@ export class BankAccount {
2229
}
2330
}
2431

25-
export class Config {
32+
class Config {
33+
host: string
34+
port: number
35+
debug: boolean
36+
2637
constructor(
27-
public host: string = 'localhost',
28-
public port: number = 3000,
29-
public debug: boolean = false,
30-
) {}
38+
host: string = 'localhost',
39+
port: number = 3000,
40+
debug: boolean = false,
41+
) {
42+
this.host = host
43+
this.port = port
44+
this.debug = debug
45+
}
3146
}
3247

3348
const user = new User('Alice', '[email protected]')
@@ -44,3 +59,28 @@ const config = new Config()
4459
const customConfig = new Config('example.com', 8080, true)
4560
console.log(`Default config: ${config.host}:${config.port}`)
4661
console.log(`Custom config: ${customConfig.host}:${customConfig.port}`)
62+
63+
const sampleAccount = new BankAccount('12345')
64+
sampleAccount.deposit(100)
65+
const balanceAfterFirstDeposit = sampleAccount.getBalance()
66+
sampleAccount.deposit(50)
67+
68+
console.log(
69+
'Results JSON:',
70+
JSON.stringify({
71+
user: { name: user.name, email: user.email, role: user.role },
72+
admin: { name: admin.name, email: admin.email, role: admin.role },
73+
account: {
74+
accountNumber: sampleAccount.accountNumber,
75+
initialBalance: 0,
76+
balanceAfterFirstDeposit,
77+
balanceAfterSecondDeposit: sampleAccount.getBalance(),
78+
},
79+
config: { host: config.host, port: config.port, debug: config.debug },
80+
customConfig: {
81+
host: customConfig.host,
82+
port: customConfig.port,
83+
debug: customConfig.debug,
84+
},
85+
}),
86+
)

0 commit comments

Comments
 (0)