Skip to content

Commit 3d5c7f4

Browse files
committed
Migrate from Playwright to Node.js built-in test runner
- Convert all test files to use node:test and node:assert/strict - Create copy-tests.js script in each epicshop/ to propagate tests from solution to problem directories - Add test scripts to all exercise package.json files - Remove Playwright config and test files - Update GitHub Actions workflow to use Node test runner Test files now use top-level await with test() calls.
1 parent 3d0cc45 commit 3d5c7f4

File tree

67 files changed

+1373
-520
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1373
-520
lines changed

.github/workflows/validate.yml

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,9 @@ jobs:
5656
- name: 📦 Install dependencies
5757
run: npm ci
5858

59-
- name: 🎭 Install Playwright Browsers
60-
run: npx playwright install --with-deps chromium
61-
working-directory: ./epicshop
62-
63-
- name: 🎭 Run Playwright tests
64-
run: npx playwright test
65-
working-directory: ./epicshop
66-
67-
- name: 📤 Upload Playwright Report
68-
uses: actions/upload-artifact@v4
69-
if: ${{ !cancelled() }}
70-
with:
71-
name: playwright-report
72-
path: epicshop/playwright-report/
73-
retention-days: 30
59+
- name: 🧪 Run tests
60+
id: run_tests
61+
run: node ./epicshop/test.js ..s
7462

7563
deploy:
7664
name: 🚀 Deploy

SETUP_STEPS.md

Lines changed: 0 additions & 44 deletions
This file was deleted.

epicshop/copy-tests.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import fs from 'node:fs'
2+
import path from 'node:path'
3+
import { fileURLToPath } from 'node:url'
4+
5+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
6+
const exercisesDir = path.join(__dirname, '..', 'exercises')
7+
8+
function findSolutionDirs(dir) {
9+
const solutionDirs = []
10+
11+
for (const exerciseDir of fs.readdirSync(dir)) {
12+
const exercisePath = path.join(dir, exerciseDir)
13+
if (!fs.statSync(exercisePath).isDirectory()) continue
14+
15+
for (const stepDir of fs.readdirSync(exercisePath)) {
16+
if (stepDir.includes('.solution.')) {
17+
solutionDirs.push(path.join(exercisePath, stepDir))
18+
}
19+
}
20+
}
21+
22+
return solutionDirs
23+
}
24+
25+
function copyTestFiles() {
26+
const solutionDirs = findSolutionDirs(exercisesDir)
27+
let copiedCount = 0
28+
29+
for (const solutionDir of solutionDirs) {
30+
const problemDir = solutionDir.replace('.solution.', '.problem.')
31+
32+
if (!fs.existsSync(problemDir)) {
33+
console.log(`⚠️ No problem dir for: ${path.basename(solutionDir)}`)
34+
continue
35+
}
36+
37+
const testFiles = fs
38+
.readdirSync(solutionDir)
39+
.filter((f) => f.endsWith('.test.ts'))
40+
41+
for (const testFile of testFiles) {
42+
const src = path.join(solutionDir, testFile)
43+
const dest = path.join(problemDir, testFile)
44+
45+
fs.copyFileSync(src, dest)
46+
console.log(`✅ Copied ${testFile} to ${path.basename(problemDir)}`)
47+
copiedCount++
48+
}
49+
}
50+
51+
console.log(`\n📋 Copied ${copiedCount} test file(s)`)
52+
}
53+
54+
copyTestFiles()

epicshop/playwright.config.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

epicshop/test.js

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,6 @@ function printTestSummary(results) {
6161

6262
async function main() {
6363
const allApps = await getApps()
64-
const allAppsWithTests = allApps.filter((app) => app.test?.type === 'script')
65-
66-
if (allAppsWithTests.length === 0) {
67-
console.error(
68-
'❌ No apps with tests were found. Ensure your apps have a test script defined in the package.json. Exiting.',
69-
)
70-
process.exit(1)
71-
}
7264

7365
let selectedApps
7466
let additionalArgs = []
@@ -82,7 +74,7 @@ async function main() {
8274

8375
if (process.argv[2]) {
8476
const patterns = process.argv[2].toLowerCase().split(',')
85-
selectedApps = allAppsWithTests.filter((app) => {
77+
selectedApps = allApps.filter((app) => {
8678
const { exerciseNumber, stepNumber, type } = app
8779

8880
return patterns.some((pattern) => {
@@ -103,10 +95,7 @@ async function main() {
10395
})
10496
} else {
10597
const displayNameMap = new Map(
106-
allAppsWithTests.map((app) => [
107-
getAppDisplayName(app, allAppsWithTests),
108-
app,
109-
]),
98+
allApps.map((app) => [getAppDisplayName(app, allApps), app]),
11099
)
111100
const choices = displayNameMap.keys()
112101

@@ -122,14 +111,14 @@ async function main() {
122111
})
123112

124113
selectedApps = response.appDisplayNames.includes('All')
125-
? allAppsWithTests
114+
? allApps
126115
: response.appDisplayNames.map((appDisplayName) =>
127116
displayNameMap.get(appDisplayName),
128117
)
129118

130119
// Update this block to use process.argv
131120
const appPattern =
132-
selectedApps.length === allAppsWithTests.length
121+
selectedApps.length === allApps.length
133122
? '*'
134123
: selectedApps
135124
.map((app) => `${app.exerciseNumber}.${app.stepNumber}.${app.type}`)

epicshop/workshop.test.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import assert from 'node:assert/strict'
2+
import { test } from 'node:test'
3+
import { price, productName, quantity, description } from './index.ts'
4+
5+
await test('price should be defined correctly', () => {
6+
assert.strictEqual(
7+
price,
8+
29.99,
9+
'🚨 price should be set to 29.99 - check that you declared it as a number',
10+
)
11+
assert.strictEqual(
12+
typeof price,
13+
'number',
14+
'🚨 price should be a number type - make sure you used a number literal, not a string',
15+
)
16+
})
17+
18+
await test('productName should be defined correctly', () => {
19+
assert.strictEqual(
20+
productName,
21+
'TypeScript Guide',
22+
'🚨 productName should be set to "TypeScript Guide" - check that you used the exact string',
23+
)
24+
assert.strictEqual(
25+
typeof productName,
26+
'string',
27+
'🚨 productName should be a string type - make sure you used quotes around the value',
28+
)
29+
})
30+
31+
await test('quantity should be defined correctly', () => {
32+
assert.strictEqual(
33+
quantity,
34+
100,
35+
'🚨 quantity should be set to 100 - check that you declared it as a number',
36+
)
37+
assert.strictEqual(
38+
typeof quantity,
39+
'number',
40+
'🚨 quantity should be a number type - make sure you used a number literal, not a string',
41+
)
42+
})
43+
44+
await test('description should be defined correctly', () => {
45+
assert.strictEqual(
46+
description,
47+
'Product: TypeScript Guide | Price: $29.99 | In Stock: 100',
48+
'🚨 description should combine productName, price, and quantity into a formatted string - use template literals or string concatenation',
49+
)
50+
assert.strictEqual(
51+
typeof description,
52+
'string',
53+
'🚨 description should be a string type - make sure you created a string value',
54+
)
55+
})

exercises/01.primitive-types/01.problem.numbers-and-strings/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "exercises_01.primitive-types_01.problem.numbers-and-strings",
33
"type": "module",
44
"scripts": {
5-
"start": "node index.ts"
5+
"start": "node index.ts",
6+
"test": "node --test index.test.ts"
67
}
78
}
Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,55 @@
1-
import { testStep, expect } from '@epic-web/workshop-utils/test'
1+
import assert from 'node:assert/strict'
2+
import { test } from 'node:test'
23
import { price, productName, quantity, description } from './index.ts'
34

4-
await testStep('price should be defined correctly', async () => {
5-
expect(
5+
await test('price should be defined correctly', () => {
6+
assert.strictEqual(
67
price,
8+
29.99,
79
'🚨 price should be set to 29.99 - check that you declared it as a number',
8-
).toBe(29.99)
9-
expect(
10+
)
11+
assert.strictEqual(
1012
typeof price,
13+
'number',
1114
'🚨 price should be a number type - make sure you used a number literal, not a string',
12-
).toBe('number')
15+
)
1316
})
1417

15-
await testStep('productName should be defined correctly', async () => {
16-
expect(
18+
await test('productName should be defined correctly', () => {
19+
assert.strictEqual(
1720
productName,
21+
'TypeScript Guide',
1822
'🚨 productName should be set to "TypeScript Guide" - check that you used the exact string',
19-
).toBe('TypeScript Guide')
20-
expect(
23+
)
24+
assert.strictEqual(
2125
typeof productName,
26+
'string',
2227
'🚨 productName should be a string type - make sure you used quotes around the value',
23-
).toBe('string')
28+
)
2429
})
2530

26-
await testStep('quantity should be defined correctly', async () => {
27-
expect(
31+
await test('quantity should be defined correctly', () => {
32+
assert.strictEqual(
2833
quantity,
34+
100,
2935
'🚨 quantity should be set to 100 - check that you declared it as a number',
30-
).toBe(100)
31-
expect(
36+
)
37+
assert.strictEqual(
3238
typeof quantity,
39+
'number',
3340
'🚨 quantity should be a number type - make sure you used a number literal, not a string',
34-
).toBe('number')
41+
)
3542
})
3643

37-
await testStep('description should be defined correctly', async () => {
38-
expect(
44+
await test('description should be defined correctly', () => {
45+
assert.strictEqual(
3946
description,
47+
'Product: TypeScript Guide | Price: $29.99 | In Stock: 100',
4048
'🚨 description should combine productName, price, and quantity into a formatted string - use template literals or string concatenation',
41-
).toBe('Product: TypeScript Guide | Price: $29.99 | In Stock: 100')
42-
expect(
49+
)
50+
assert.strictEqual(
4351
typeof description,
52+
'string',
4453
'🚨 description should be a string type - make sure you created a string value',
45-
).toBe('string')
54+
)
4655
})

exercises/01.primitive-types/01.solution.numbers-and-strings/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "exercises_01.primitive-types_01.solution.numbers-and-strings",
33
"type": "module",
44
"scripts": {
5-
"start": "node index.ts"
5+
"start": "node index.ts",
6+
"test": "node --test index.test.ts"
67
}
78
}

0 commit comments

Comments
 (0)