Skip to content

Commit

Permalink
Merge pull request #4 from nearform/a02-verify
Browse files Browse the repository at this point in the history
Add verify feature to the workshop
  • Loading branch information
alfonsograziano committed Feb 15, 2024
2 parents d2cb8cd + 4277ead commit 0a43d8e
Show file tree
Hide file tree
Showing 26 changed files with 553 additions and 98 deletions.
18 changes: 9 additions & 9 deletions slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -603,24 +603,24 @@ test('delayedHello executes the callback after the specified delay', () => {

- In this exercise about context, we will focus on child tests (also known as subtests)
- In the file `index.test.js` you will find multiple tests for the `sum` and the `average` functions
- Group together all the subtests related to the same function
- Group together all the subtests related to the same function using the `describe` function

---

# A12 Solution 💡

```javascript
// Grouping tests for `sum` function
test('sum function tests', async t => {
await t.test('Sum works correctly with valid input', () => {
describe('sum function tests', () => {
test('Sum works correctly with valid input', () => {
assert.deepStrictEqual(sum([1, 2, 3]), 6)
})

await t.test('Sum returns 0 in case of empty array', () => {
test('Sum returns 0 in case of empty array', () => {
assert.deepStrictEqual(sum([]), 0)
})

await t.test('Sum throws in case of bad input', () => {
test('Sum throws in case of bad input', () => {
assert.throws(() => sum('abc'), {
message: 'Input must be an array of numbers'
})
Expand All @@ -634,16 +634,16 @@ test('sum function tests', async t => {

```javascript
// Grouping tests for `average` function
test('average function tests', async t => {
await t.test('Average works correctly with valid input', () => {
describe('average function tests', () => {
test('Average works correctly with valid input', () => {
assert.deepStrictEqual(average([1, 2, 3]), 2)
})

await t.test('Average returns 0 in case of empty array', () => {
test('Average returns 0 in case of empty array', () => {
assert.deepStrictEqual(average([]), 0)
})

await t.test('Average throws in case of bad input', () => {
test('Average throws in case of bad input', () => {
assert.throws(() => average('abc'), {
message: 'Input must be an array of numbers'
})
Expand Down
3 changes: 2 additions & 1 deletion src/a02-assertions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"test": "test"
},
"scripts": {
"test": "node --test"
"test": "node --test",
"verify": "node --test NODE_NO_WARNINGS=1 --loader=../../verify/loader.js ./verifiers/handler.js"
},
"keywords": [],
"author": "",
Expand Down
86 changes: 86 additions & 0 deletions src/a02-assertions/verifiers/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { test } from '../../../verify/test.verify.js'
import { assertCalls } from '../../../verify/assert.verify.js'
import { sum, sumAsync } from './index.verify.js'

await import('../test/index.test.js')

// I'm creating this wrapper in order to be able to spy the process.exit
process.on('exit', () => {
console.log('Validating the test completion...')

const expectations = [
{
condition: test.mock.calls.length < 2,
message:
'You need to create a test for both the sum and sumAsync functions'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sum' && a.method === 'deepStrictEqual'
) === 'undefined',
message: 'You need to call "deepStrictEqual" inside the "sum" test'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sum' && a.method === 'ok'
) === 'undefined',
message: 'You need to call "ok" inside the "sum" test'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sum' && a.method === 'doesNotThrow'
) === 'undefined',
message: 'You need to call "doesNotThrow" inside the "sum" test'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sum' && a.method === 'throws'
) === 'undefined',
message: 'You need to call "throws" inside the "sum" test'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sumAsync' && a.method === 'deepStrictEqual'
) === 'undefined',
message: 'You need to call "deepStrictEqual" inside the "sumAsync" test'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sumAsync' && a.method === 'ok'
) === 'undefined',
message: 'You need to call "ok" inside the "sumAsync" test'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sumAsync' && a.method === 'doesNotReject'
) === 'undefined',
message: 'You need to call "doesNotReject" inside the "sumAsync" test'
},
{
condition:
typeof assertCalls.find(
a => a.testName === 'sumAsync' && a.method === 'rejects'
) === 'undefined',
message: 'You need to call "rejects" inside the "sumAsync" test'
},
{
condition: sum.mock.calls.length < 1,
message: 'You need to call "sum" at least once in your test'
},
{
condition: sumAsync.mock.calls.length < 1,
message: 'You need to call "sumAsync" at least once in your test'
}
]

for (const expectation of expectations) {
if (expectation.condition) throw new Error(expectation.message)
}
})
8 changes: 8 additions & 0 deletions src/a02-assertions/verifiers/index.verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {
sum as originalSum,
sumAsync as originalSumAsync
} from '../src/index.js'
import { mock } from 'node:test'

export const sum = mock.fn(originalSum)
export const sumAsync = mock.fn(originalSumAsync)
1 change: 1 addition & 0 deletions src/a04-hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"scripts": {
"test": "node --test ./test/index.test.js",
"verify": "node --test NODE_NO_WARNINGS=1 --loader=../../verify/loader.js ./verifiers/handler.js",
"solution": "node --test ./test/solution.test.js"
},
"keywords": [],
Expand Down
76 changes: 37 additions & 39 deletions src/a04-hooks/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,45 @@ let user

databaseConnection = await connectToDatabase()

test('Authentication Module Tests', async () => {
await test('should authenticate a valid user', async () => {
user = await createUser(databaseConnection, 'testuser', 'password123')
const result = await authenticateUser(
databaseConnection,
'testuser',
'password123'
)
assert.strictEqual(result, true, 'Authentication should succeed')
await deleteUser(databaseConnection, user)
})
test('should authenticate a valid user', async () => {
user = await createUser(databaseConnection, 'testuser', 'password123')
const result = await authenticateUser(
databaseConnection,
'testuser',
'password123'
)
assert.strictEqual(result, true, 'Authentication should succeed')
await deleteUser(databaseConnection, user)
})

await test('should reject invalid password', async () => {
user = await createUser(databaseConnection, 'testuser', 'password123')
const result = await authenticateUser(
databaseConnection,
'testuser',
'wrongpassword'
)
assert.strictEqual(
result,
false,
'Authentication should fail with incorrect password'
)
await deleteUser(databaseConnection, user)
})
test('should reject invalid password', async () => {
user = await createUser(databaseConnection, 'testuser', 'password123')
const result = await authenticateUser(
databaseConnection,
'testuser',
'wrongpassword'
)
assert.strictEqual(
result,
false,
'Authentication should fail with incorrect password'
)
await deleteUser(databaseConnection, user)
})

await test('should reject non-existing user', async () => {
user = await createUser(databaseConnection, 'testuser', 'password123')
const result = await authenticateUser(
databaseConnection,
'nonexistentuser',
'password123'
)
assert.strictEqual(
result,
false,
'Authentication should fail with non-existing user'
)
await deleteUser(databaseConnection, user)
})
test('should reject non-existing user', async () => {
user = await createUser(databaseConnection, 'testuser', 'password123')
const result = await authenticateUser(
databaseConnection,
'nonexistentuser',
'password123'
)
assert.strictEqual(
result,
false,
'Authentication should fail with non-existing user'
)
await deleteUser(databaseConnection, user)
})

await closeDatabaseConnection(databaseConnection)
64 changes: 31 additions & 33 deletions src/a04-hooks/test/solution.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +27,37 @@ afterEach(async () => {
await deleteUser(databaseConnection, user)
})

test('Authentication Module Tests', async () => {
await test('should authenticate a valid user', async () => {
const result = await authenticateUser(
databaseConnection,
'testuser',
'password123'
)
assert.strictEqual(result, true, 'Authentication should succeed')
})
test('should authenticate a valid user', async () => {
const result = await authenticateUser(
databaseConnection,
'testuser',
'password123'
)
assert.strictEqual(result, true, 'Authentication should succeed')
})

await test('should reject invalid password', async () => {
const result = await authenticateUser(
databaseConnection,
'testuser',
'wrongpassword'
)
assert.strictEqual(
result,
false,
'Authentication should fail with incorrect password'
)
})
test('should reject invalid password', async () => {
const result = await authenticateUser(
databaseConnection,
'testuser',
'wrongpassword'
)
assert.strictEqual(
result,
false,
'Authentication should fail with incorrect password'
)
})

await test('should reject non-existing user', async () => {
const result = await authenticateUser(
databaseConnection,
'nonexistentuser',
'password123'
)
assert.strictEqual(
result,
false,
'Authentication should fail with non-existing user'
)
})
test('should reject non-existing user', async () => {
const result = await authenticateUser(
databaseConnection,
'nonexistentuser',
'password123'
)
assert.strictEqual(
result,
false,
'Authentication should fail with non-existing user'
)
})
50 changes: 50 additions & 0 deletions src/a04-hooks/verifiers/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { test } from '../../../verify/test.verify.js'
import { fnCalls } from './index.verify.js'

await import('../test/index.test.js')

// I'm creating this wrapper in order to be able to spy the process.exit
process.on('exit', () => {
console.log('Validating the test completion...')

const expectations = [
{
condition: test.mock.calls.length < 3,
message: 'You need to create a test for at least three cases'
},
{
condition:
typeof fnCalls.find(
call => call.name === 'connectToDatabase' && call.caller === 'before'
) === 'undefined',
message: 'You need to call "connectToDatabase" inside a "before" hook'
},
{
condition:
typeof fnCalls.find(
call => call.name === 'createUser' && call.caller === 'beforeEach'
) === 'undefined',
message: 'You need to call "createUser" inside a "beforeEach" hook'
},
{
condition:
typeof fnCalls.find(
call => call.name === 'deleteUser' && call.caller === 'afterEach'
) === 'undefined',
message: 'You need to call "deleteUser" inside a "afterEach" hook'
},
{
condition:
typeof fnCalls.find(
call =>
call.name === 'closeDatabaseConnection' && call.caller === 'after'
) === 'undefined',
message:
'You need to call "closeDatabaseConnection" inside a "after" hook'
}
]

for (const expectation of expectations) {
if (expectation.condition) throw new Error(expectation.message)
}
})
Loading

0 comments on commit 0a43d8e

Please sign in to comment.