Skip to content

Commit 9231c48

Browse files
Add concept exercise test with type tests (#74)
1 parent 62f30a3 commit 9231c48

26 files changed

+746
-15
lines changed

.vscode/settings.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,11 @@
66
"eslint.nodePath": ".yarn/sdks",
77
"prettier.prettierPath": ".yarn/sdks/prettier/index.cjs",
88
"typescript.tsdk": ".yarn/sdks/typescript/lib",
9-
"typescript.enablePromptUseWorkspaceTsdk": true
9+
"typescript.enablePromptUseWorkspaceTsdk": true,
10+
"cSpell.words": [
11+
"corepack",
12+
"estree",
13+
"exercism",
14+
"tstyche"
15+
]
1016
}

bin/run.sh

+71-14
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ if [[ "${OUTPUT}" =~ "$ROOT" ]]; then
166166

167167
echo "✔️ tsconfig.json from root to output"
168168
cp "${ROOT}/tsconfig.solutions.json" "${OUTPUT}tsconfig.json"
169+
170+
if test -f "${OUTPUT}yarn.lock"; then
171+
echo "✔️ renaming yarn.lock in output to prevent yarn from "
172+
echo " interpreting this directory as a standalone package."
173+
mv "${OUTPUT}yarn.lock" "${OUTPUT}yarn.lock.💥.bak" || true
174+
fi;
175+
169176
echo ""
170177
else
171178
echo ""
@@ -256,7 +263,9 @@ else
256263

257264
if test -f "${OUTPUT}package.json.💥.bak"; then
258265
echo "✔️ restoring package.json in output"
259-
unlink "${OUTPUT}package.json"
266+
if test -f "${OUTPUT}package.json"; then
267+
unlink "${OUTPUT}package.json"
268+
fi
260269
mv "${OUTPUT}package.json.💥.bak" "${OUTPUT}package.json" || true
261270
fi;
262271

@@ -265,8 +274,16 @@ else
265274
mv "${OUTPUT}tsconfig.json.💥.bak" "${OUTPUT}tsconfig.json" || true
266275
fi;
267276

277+
if test -f "${OUTPUT}yarn.lock.💥.bak"; then
278+
echo "✔️ restoring yarn.lock in output"
279+
if test -f "${OUTPUT}yarn.lock"; then
280+
unlink "${OUTPUT}yarn.lock"
281+
fi
282+
mv "${OUTPUT}yarn.lock.💥.bak" "${OUTPUT}yarn.lock" || true
283+
fi;
284+
268285
result="The submitted code cannot be ran by the test-runner. There is no configuration file inside the .meta (or .exercism) directory, and the fallback test file '${test_file}' does not exist. Please fix these issues and resubmit."
269-
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"$result\" }" > $result_file
286+
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"${result}\" }" > $result_file
270287
sed -Ei ':a;N;$!ba;s/\r{0,1}\n/\\n/g' $result_file
271288

272289
echo "❌ could not run the test suite(s). A valid output exists:"
@@ -366,7 +383,9 @@ if [ $test_exit -eq 2 ]; then
366383

367384
if test -f "${OUTPUT}package.json.💥.bak"; then
368385
echo "✔️ restoring package.json in output"
369-
unlink "${OUTPUT}package.json"
386+
if test -f "${OUTPUT}package.json"; then
387+
unlink "${OUTPUT}package.json"
388+
fi
370389
mv "${OUTPUT}package.json.💥.bak" "${OUTPUT}package.json" || true
371390
fi;
372391

@@ -376,14 +395,22 @@ if [ $test_exit -eq 2 ]; then
376395
mv "${OUTPUT}tsconfig.json.💥.bak" "${OUTPUT}tsconfig.json" || true
377396
fi;
378397

398+
if test -f "${OUTPUT}yarn.lock.💥.bak"; then
399+
echo "✔️ restoring yarn.lock in output"
400+
if test -f "${OUTPUT}yarn.lock"; then
401+
unlink "${OUTPUT}yarn.lock"
402+
fi
403+
mv "${OUTPUT}yarn.lock.💥.bak" "${OUTPUT}yarn.lock" || true
404+
fi;
405+
379406
# Compose the message to show to the student
380407
#
381408
# TODO: interpret the tsc_result lines and pull out the source.
382409
# We actually already have code to do this, given the cursor position
383410
#
384-
tsc_result=$(cat $result_file | jq -Rsa . | sed -e 's/^"//' -e 's/"$//')
385-
tsc_result="The submitted code didn't compile. We have collected the errors encountered during compilation. At this moment the error messages are not very read-friendly, but it's a start. We are working on a more helpful output.\n-------------------------------\n$tsc_result"
386-
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"$tsc_result\" }" > $result_file
411+
tsc_result="$(cat $result_file | jq -Rsa . | sed -e 's/^"//' -e 's/"$//')"
412+
tsc_result="The submitted code didn't compile. We have collected the errors encountered during compilation. At this moment the error messages are not very read-friendly, but it's a start. We are working on a more helpful output.\n-------------------------------\n${tsc_result}"
413+
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"${tsc_result}\" }" > $result_file
387414
sed -Ei ':a;N;$!ba;s/\r{0,1}\n/\\n/g' $result_file
388415

389416
echo "❌ tsc compilation failed with a valid output:"
@@ -424,14 +451,14 @@ if test -d "${OUTPUT}__typetests__/"; then
424451
echo ""
425452
cd "${OUTPUT}" && corepack yarn tstyche --failFast 2> "${OUTPUT}tstyche.stderr.txt" 1> "${OUTPUT}tstyche.stdout.txt"
426453

427-
tstyche_error_output=$(cat "${OUTPUT}tstyche.stderr.txt")
454+
tstyche_error_output="$(cat "${OUTPUT}tstyche.stderr.txt")"
428455

429456
if [ -z "${tstyche_error_output}" ]; then
430457
echo "✅ all tests (*.tst.ts) passed."
431458
else
432-
tstyche_result=$(echo $tstyche_error_output | jq -Rsa . | sed -e 's/^"//' -e 's/"$//')
459+
tstyche_result=$(echo "${tstyche_error_output}" | jq -Rsa . | sed -e 's/^"//' -e 's/"$//' | sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g')
433460
tstyche_result="The submitted code did compile but at least one of the type-tests failed. We have collected the failing test encountered. At this moment the error messages are not very read-friendly, but it's a start. We are working on a more helpful output.\n-------------------------------\n${tstyche_result}"
434-
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"$tstyche_result\" }" > $result_file
461+
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"${tstyche_result}\" }" > $result_file
435462
sed -Ei ':a;N;$!ba;s/\r{0,1}\n/\\n/g' $result_file
436463

437464
echo "❌ not all tests (*.tst.ts) passed."
@@ -450,7 +477,9 @@ if test -d "${OUTPUT}__typetests__/"; then
450477

451478
if test -f "${OUTPUT}package.json.💥.bak"; then
452479
echo "✔️ restoring package.json in output"
453-
unlink "${OUTPUT}package.json"
480+
if test -f "${OUTPUT}package.json"; then
481+
unlink "${OUTPUT}package.json"
482+
fi
454483
mv "${OUTPUT}package.json.💥.bak" "${OUTPUT}package.json" || true
455484
fi;
456485

@@ -459,6 +488,14 @@ if test -d "${OUTPUT}__typetests__/"; then
459488
mv "${OUTPUT}tsconfig.json.💥.bak" "${OUTPUT}tsconfig.json" || true
460489
fi;
461490

491+
if test -f "${OUTPUT}yarn.lock.💥.bak"; then
492+
echo "✔️ restoring yarn.lock in output"
493+
if test -f "${OUTPUT}yarn.lock"; then
494+
unlink "${OUTPUT}yarn.lock"
495+
fi
496+
mv "${OUTPUT}yarn.lock.💥.bak" "${OUTPUT}yarn.lock" || true
497+
fi;
498+
462499
echo ""
463500
echo "---------------------------------------------------------------"
464501
echo "The results of this run have been written to 'results.json'."
@@ -496,11 +533,11 @@ if [ -z "${jest_tests}" ]; then
496533

497534
# TODO: use results from tstyche
498535
runner_result="The type tests ran correctly. We are working on showing the individual tests results but for now, everything is fine!"
499-
echo "{ \"version\": 1, \"status\": \"pass\", \"message\": \"$runner_result\" }" > $result_file
536+
echo "{ \"version\": 1, \"status\": \"pass\", \"message\": \"${runner_result}\" }" > $result_file
500537
else
501538
echo "❌ neither type tests, nor execution tests ran"
502539
runner_result="The submitted code was not subjected to any type or execution tests. It did compile correctly, but something is wrong because at least one test was expected."
503-
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"$runner_result\" }" > $result_file
540+
echo "{ \"version\": 1, \"status\": \"error\", \"message\": \"${runner_result}\" }" > $result_file
504541
sed -Ei ':a;N;$!ba;s/\r{0,1}\n/\\n/g' $result_file
505542
fi
506543

@@ -518,7 +555,9 @@ if [ -z "${jest_tests}" ]; then
518555

519556
if test -f "${OUTPUT}package.json.💥.bak"; then
520557
echo "✔️ restoring package.json in output"
521-
unlink "${OUTPUT}package.json"
558+
if test -f "${OUTPUT}package.json"; then
559+
unlink "${OUTPUT}package.json"
560+
fi
522561
mv "${OUTPUT}package.json.💥.bak" "${OUTPUT}package.json" || true
523562
fi;
524563

@@ -527,6 +566,14 @@ if [ -z "${jest_tests}" ]; then
527566
mv "${OUTPUT}tsconfig.json.💥.bak" "${OUTPUT}tsconfig.json" || true
528567
fi;
529568

569+
if test -f "${OUTPUT}yarn.lock.💥.bak"; then
570+
echo "✔️ restoring yarn.lock in output"
571+
if test -f "${OUTPUT}yarn.lock"; then
572+
unlink "${OUTPUT}yarn.lock"
573+
fi
574+
mv "${OUTPUT}yarn.lock.💥.bak" "${OUTPUT}yarn.lock" || true
575+
fi;
576+
530577
echo ""
531578
echo "---------------------------------------------------------------"
532579
echo "The results of this run have been written to 'results.json'."
@@ -581,7 +628,9 @@ fi;
581628

582629
if test -f "${OUTPUT}package.json.💥.bak"; then
583630
echo "✔️ restoring package.json in output"
584-
unlink "${OUTPUT}package.json"
631+
if test -f "${OUTPUT}package.json"; then
632+
unlink "${OUTPUT}package.json"
633+
fi
585634
mv "${OUTPUT}package.json.💥.bak" "${OUTPUT}package.json" || true
586635
fi;
587636

@@ -590,6 +639,14 @@ if test -f "${OUTPUT}tsconfig.json.💥.bak"; then
590639
mv "${OUTPUT}tsconfig.json.💥.bak" "${OUTPUT}tsconfig.json" || true
591640
fi;
592641

642+
if test -f "${OUTPUT}yarn.lock.💥.bak"; then
643+
echo "✔️ restoring yarn.lock in output"
644+
if test -f "${OUTPUT}yarn.lock"; then
645+
unlink "${OUTPUT}yarn.lock"
646+
fi
647+
mv "${OUTPUT}yarn.lock.💥.bak" "${OUTPUT}yarn.lock" || true
648+
fi;
649+
593650
echo ""
594651
echo "---------------------------------------------------------------"
595652
echo "The results of this run have been written to 'results.json'."

test/dev.test.mjs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { join } from 'node:path'
2+
import shelljs from 'shelljs'
3+
import { assertPass } from './asserts.mjs'
4+
import { fixtures } from './paths.mjs'
5+
6+
// run this file like:
7+
// corepack yarn dlx cross-env SILENT=0 corepack yarn node test/dev.test.mjs
8+
9+
shelljs.echo(
10+
'typescript-test-runner > passing solution (jest + tstyche) > no output directory'
11+
)
12+
assertPass(
13+
'lasagna',
14+
join(fixtures, 'lasagna', 'pass'),
15+
join(fixtures, 'lasagna', 'pass')
16+
)
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Hints
2+
3+
## 1. Define the expected oven time in minutes
4+
5+
- Define a [constant][constants] which should contain the [`number`][numbers] value specified in the recipe.
6+
- [`export`][export] the constant.
7+
8+
## 2. Calculate the remaining oven time in minutes
9+
10+
- [Explicitly return a number][return] from the function.
11+
- Use the [mathematical operator for subtraction][operators] to subtract values.
12+
13+
## 3. Calculate the preparation time in minutes
14+
15+
- [Explicitly return a number][return] from the function.
16+
- Use the [mathematical operator for multiplication][operators] to multiply values.
17+
- Use the extra constant for the time in minutes per layer.
18+
19+
## 4. Calculate the total working time in minutes
20+
21+
- [Explicitly return a number][return] from the function.
22+
- [Invoke][invocation] one of the other methods implemented previously.
23+
- Use the [mathematical operator for addition][operators] to add values.
24+
25+
[return]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Return_values
26+
[export]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
27+
[operators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators
28+
[constants]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
29+
[invocation]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Calling_functions
30+
[numbers]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Instructions
2+
3+
Lucian's girlfriend is on her way home, and he hasn't cooked their anniversary dinner!
4+
5+
In this exercise, you're going to write some code to help Lucian cook an exquisite lasagna from his favorite cookbook.
6+
7+
You have four tasks related to the time spent cooking the lasagna.
8+
9+
## 1. Define the expected oven time in minutes
10+
11+
Define the `EXPECTED_MINUTES_IN_OVEN` constant that represents how many minutes the lasagna should be in the oven. It must be exported. According to the cooking book, the expected oven time in minutes is `40`.
12+
13+
## 2. Calculate the remaining oven time in minutes
14+
15+
Implement the `remainingMinutesInOven` function that takes the actual minutes the lasagna has been in the oven as a _parameter_ and _returns_ how many minutes the lasagna still has to remain in the oven, based on the **expected oven time in minutes** from the previous task.
16+
17+
```javascript
18+
remainingMinutesInOven(30)
19+
// => 10
20+
```
21+
22+
## 3. Calculate the preparation time in minutes
23+
24+
Implement the `preparationTimeInMinutes` function that takes the number of layers you added to the lasagna as a _parameter_ and _returns_ how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare.
25+
26+
```javascript
27+
preparationTimeInMinutes(2)
28+
// => 4
29+
```
30+
31+
## 4. Calculate the total working time in minutes
32+
33+
Implement the `totalTimeInMinutes` function that takes _two parameters_: the `numberOfLayers` parameter is the number of layers you added to the lasagna, and the `actualMinutesInOven` parameter is the number of minutes the lasagna has been in the oven. The function should _return_ how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment.
34+
35+
```javascript
36+
totalTimeInMinutes(3, 20)
37+
// => 26
38+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Introduction
2+
3+
JavaScript is a dynamic language, supporting object-oriented, imperative, and declarative (e.g. functional programming) styles.
4+
5+
## (Re-)Assignment
6+
7+
There are a few primary ways to assign values to names in JavaScript - using variables or constants. On Exercism, variables are always written in [camelCase][wiki-camel-case]; constants are written in [SCREAMING_SNAKE_CASE][wiki-snake-case]. There is no official guide to follow, and various companies and organizations have various style guides. _Feel free to write variables any way you like_. The upside from writing them the way the exercises are prepared is that they'll be highlighted differently in the web interface and most IDEs.
8+
9+
Variables in JavaScript can be defined using the [`const`][mdn-const], [`let`][mdn-let] or [`var`][mdn-var] keyword.
10+
11+
A variable can reference different values over its lifetime when using `let` or `var`. For example, `myFirstVariable` can be defined and redefined many times using the assignment operator `=`:
12+
13+
```javascript
14+
let myFirstVariable = 1
15+
myFirstVariable = 'Some string'
16+
myFirstVariable = new SomeComplexClass()
17+
```
18+
19+
In contrast to `let` and `var`, variables that are defined with `const` can only be assigned once. This is used to define constants in JavaScript.
20+
21+
```javascript
22+
const MY_FIRST_CONSTANT = 10
23+
24+
// Can not be re-assigned.
25+
MY_FIRST_CONSTANT = 20
26+
// => TypeError: Assignment to constant variable.
27+
```
28+
29+
> 💡 In a later Concept Exercise the difference between _constant_ assignment / binding and _constant_ value is explored and explained.
30+
31+
## Function Declarations
32+
33+
In JavaScript, units of functionality are encapsulated in _functions_, usually grouping functions together in the same file if they belong together. These functions can take parameters (arguments), and can _return_ a value using the `return` keyword. Functions are invoked using `()` syntax.
34+
35+
```javascript
36+
function add(num1, num2) {
37+
return num1 + num2
38+
}
39+
40+
add(1, 3)
41+
// => 4
42+
```
43+
44+
> 💡 In JavaScript there are _many_ different ways to declare a function. These other ways look different than using the `function` keyword. The track tries to gradually introduce them, but if you already know about them, feel free to use any of them. In most cases, using one or the other isn't better or worse.
45+
46+
## Exposing to Other Files
47+
48+
To make a `function`, a constant, or a variable available in _other files_, they need to be [exported][mdn-export] using the `export` keyword. Another file may then [import][mdn-import] these using the `import` keyword. This is also known as the module system. A great example is how all the tests work. Each exercise has at least one file, for example `lasagna.js`, which contains the _implementation_. Additionally there is at least one other file, for example `lasagna.spec.js`, that contains the _tests_. This file _imports_ the public (i.e. exported) entities in order to test the implementation:
49+
50+
```javascript
51+
// file.js
52+
export const MY_VALUE = 10
53+
54+
export function add(num1, num2) {
55+
return num1 + num2
56+
}
57+
58+
// file.spec.js
59+
import { MY_VALUE, add } from './file'
60+
61+
add(MY_VALUE, 5)
62+
// => 15
63+
```
64+
65+
[mdn-const]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
66+
[mdn-export]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
67+
[mdn-import]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
68+
[mdn-let]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
69+
[mdn-var]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
70+
[wiki-camel-case]: https://en.wikipedia.org/wiki/Camel_case
71+
[wiki-snake-case]: https://en.wikipedia.org/wiki/Snake_case
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"authors": ["SleeplessByte"],
3+
"files": {
4+
"solution": [
5+
"lasagna.ts"
6+
],
7+
"test": [
8+
"__typetests__/lasagna.tst.ts",
9+
"lasagna.test.ts"
10+
],
11+
"exemplar": [
12+
".meta/exemplar.ts"
13+
]
14+
},
15+
"forked_from": [
16+
"javascript/lasagna"
17+
],
18+
"blurb": "Learn the basics of TypeScript cooking a brilliant lasagna from your favorite cooking book.",
19+
"custom": {
20+
"version.tests.compatibility": "jest-29",
21+
"flag.tests.task-per-describe": true,
22+
"flag.tests.may-run-long": false,
23+
"flag.tests.includes-optional": false,
24+
"flag.tests.jest": true,
25+
"flag.tests.tstyche": true
26+
}
27+
}

0 commit comments

Comments
 (0)