Skip to content

Commit 02e6862

Browse files
authored
Detect extra test by group names (#3)
* Detect extra test by group names * Update readme
1 parent afe3fb5 commit 02e6862

File tree

8 files changed

+136
-4
lines changed

8 files changed

+136
-4
lines changed

README.md

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ This package provides Jest helpers for usage in a skills competition environment
88

99
- [Installation](#installation)
1010
- [Usage](#usage)
11+
- [Grouping](#grouping)
12+
- [Extra tests](#extra-tests)
1113
- [License](#license)
1214

1315
## Installation
1416

1517
**Requirements:**
1618

1719
- Node `22` or greater
20+
- Jest `30` or greater
1821

1922
To install this package, run the following command:
2023

@@ -26,8 +29,8 @@ It is suggested to add the following npm scripts:
2629

2730
```json
2831
"scripts": {
29-
"test": "jest",
30-
"test:json": "cross-env SKILLS17_JSON=true jest"
32+
"test": "jest",
33+
"test:json": "cross-env SKILLS17_JSON=true jest"
3134
},
3235
```
3336

@@ -61,6 +64,66 @@ folder of your task, next to the `package.json` file.
6164
See the [`@skills17/task-config`](https://github.com/skills17/task-config#configuration) package for a detailed
6265
description of all available properties in the `config.yaml` file.
6366

67+
### Grouping
68+
69+
A core concept is test groups. You usually don't want to test everything for one criterion in one
70+
test function but instead split it into multiple ones for a cleaner test class and a better overview.
71+
72+
In JS, tests are grouped by a test name prefix defined in the `config.yaml` file.
73+
74+
All `describe`s are concatenated with the actual test names before evaluation.
75+
76+
For example, the following test will have the name `Countries > Overview > lists all countries`:
77+
78+
```typescript
79+
describe('Countries', () => {
80+
describe('Overview', () => {
81+
it('lists all countries', () => {
82+
// ...
83+
});
84+
});
85+
});
86+
```
87+
88+
To catch and group all tests within the `Overview` description, the group matcher can be set to
89+
`Countries > Overview > .+` for example. Each of the tests within that group will now award 1 point
90+
to the group.
91+
92+
### Extra tests
93+
94+
To prevent cheating, extra tests can be used.
95+
They are not available to the competitors and should test the same things as the normal tests do,
96+
but with different values.
97+
98+
For example, if your normal test contains a check to search the list of all countries by 'Sw*', copy
99+
the test into an extra test and change the search string to 'Ca*'.
100+
Since the competitors will not know the extra test, it would detect statically returned values that
101+
were returned to satisfy the 'Sw*' tests instead of actually implement the search logic.
102+
103+
Extra tests are detected by their `describe`, which should equal `'Extra'` or `'extra'`. That means
104+
that you can wrap your test in an additional extra `describe` like shown below. The other
105+
`describe`s and test names should equal the ones from the normal tests. If they don't, a warning
106+
will be displayed.
107+
108+
```typescript
109+
describe('Extra', () => { // <-- only this describe has to be added
110+
describe('Countries', () => {
111+
it('lists all countries', () => {
112+
// ...
113+
});
114+
});
115+
});
116+
```
117+
118+
It usually makes sense to move the extra tests in a separate folder, so the folder can be deleted
119+
before the tasks are distributed to the competitors.
120+
Nothing else needs to be done or configured.
121+
122+
If an extra test fails while the corresponding normal test passes, a warning will be displayed that
123+
a manual review of that test is required since it detected possible cheating.
124+
The penalty then has to be decided manually from case to case, the points visible in the output
125+
assumed that the test passed and there was no cheating.
126+
64127
## License
65128

66129
[MIT](https://github.com/skills17/jest-helpers/blob/master/LICENSE)

src/skills17-reporter.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,11 @@ export default class Skills17Reporter implements Reporter {
4343
}
4444

4545
onTestResult(test: Test, testResult: TestResult, _aggregatedResults: AggregatedResult): void {
46-
const isExtra = test.path.includes('/extra/');
46+
const isExtraPath = test.path.includes('/extra/');
4747
for (const result of testResult.testResults) {
48+
const isExtra = isExtraPath || result.ancestorTitles.map(title => title.toLowerCase()).includes('extra');
4849
this.testRun?.recordTest(
49-
`${result.ancestorTitles.join(' > ')} > ${result.title}`,
50+
`${result.ancestorTitles.filter(title => title.toLowerCase() !== 'extra').join(' > ')} > ${result.title}`,
5051
result.title,
5152
isExtra,
5253
result.status === 'passed',
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# yaml-language-server: $schema=https://schema.skills17.ch/task-config/v3/config.schema.json
2+
id: basic-functionality
3+
groups:
4+
- match: example.+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"testResults": [
3+
{
4+
"group": "example.+",
5+
"points": 1,
6+
"maxPoints": 1,
7+
"strategy": "add",
8+
"manualCheck": true,
9+
"tests": [
10+
{
11+
"name": "adds 1 + 2 to equal 3",
12+
"points": 1,
13+
"maxPoints": 1,
14+
"successful": true,
15+
"required": false,
16+
"manualCheck": true
17+
}
18+
]
19+
}
20+
]
21+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
------------ RESULT ------------
2+
3+
Summary:
4+
example.+: 1/1 point [manual check required]
5+
? adds 1 + 2 to equal 3 please check manually for static return values and/or logical errors
6+
7+
Total: 1/1 point
8+
9+
Info: The detailed test and error information is visible above the result summary.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import process from 'node:process';
2+
import {type JestConfigWithTsJest} from 'ts-jest';
3+
4+
const jsonOnlyReport = Boolean(process.env.SKILLS17_JSON);
5+
6+
const config: JestConfigWithTsJest = {
7+
clearMocks: true,
8+
reporters: jsonOnlyReport
9+
? [['../../../lib/skills17-reporter', {json: jsonOnlyReport}]]
10+
: ['../../../lib/skills17-reporter'],
11+
testEnvironment: 'node',
12+
};
13+
14+
export default config;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function sum(a, b) {
2+
return a + b;
3+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import sum from './example.js';
2+
3+
/* eslint-disable no-undef */
4+
describe('example', () => {
5+
test('adds 1 + 2 to equal 3', () => {
6+
expect(sum(1, 2)).toBe(3);
7+
});
8+
});
9+
10+
describe('extra', () => {
11+
describe('example', () => {
12+
test('adds 1 + 2 to equal 3', () => {
13+
expect(sum(0, 0)).toBe(1);
14+
});
15+
});
16+
});
17+
/* eslint-enable no-undef */

0 commit comments

Comments
 (0)