Skip to content
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: API CI

on:
pull_request:
branches:
- main
push:
branches:
- main
- "ci/**"
workflow_dispatch:

permissions:
contents: read

jobs:
test-and-lint:
name: Tests and lint
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Run Jest tests
run: npm test -- --runInBand

- name: Run ESLint
run: npm run lint
6 changes: 3 additions & 3 deletions api/routes/exercises/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,12 @@ const parsePagination = (pageParam, limitParam, lang) => {
: errorMessages.invalidPage[lang],
);
}
if (!Number.isSafeInteger(limit) || limit < 1) {
return validationError(errorMessages.invalidLimit[lang]);
}
if (limit > maxLimit) {
return validationError(errorMessages.limitTooLarge[lang]);
}
if (!Number.isSafeInteger(limit) || limit < 1) {
return validationError(errorMessages.invalidLimit[lang]);
}

if (!Number.isSafeInteger(page * limit)) {
return validationError(errorMessages.offsetTooLarge[lang].replace(
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const nodeGlobals = {
__dirname: "readonly",
Buffer: "readonly",
console: "readonly",
fetch: "readonly",
global: "readonly",
module: "readonly",
process: "readonly",
Expand Down
24 changes: 23 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"node": ">=20 <23"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"eslint": "^10.4.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
Expand Down
2 changes: 1 addition & 1 deletion test/routes/exercises.filters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,6 @@ describe("GET /api/exercises/filters", () => {
const response = await request(app).get("/api/exercises/filters");
expect(response.status).toBe(500);
expect(response.body.message).toBe("Error fetching exercises.");
expect(response.body.error).toBe("DB connection lost");
expect(response.body).not.toHaveProperty("error");
});
});
2 changes: 1 addition & 1 deletion test/routes/exercises.list.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ describe("exercise list database filtering and pagination", () => {
expect(response.status).toBe(500);
expect(response.body).toEqual({
message: errorMessages.fetchError.es,
error: "Database unavailable",
});
expect(response.body).not.toHaveProperty("error");
});
});
4 changes: 2 additions & 2 deletions test/routes/exercises.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ describe("exercise routes", () => {

it.each([
["limit=1000000", "The 'limit' parameter must not exceed 100."],
["limit=10abc", "parameter 'limit' is invalid. use a value greater than 0"],
["limit=10abc", "parameter 'limit' is invalid. use a value greater than 0."],
["page=1abc", "parameter 'page' is invalid. use a value greater than or equal to 0."],
["page=-1", "parameter 'page' is invalid. use a value greater than or equal to 0."],
["page=9007199254740992", "The 'page' parameter must not exceed 9007199254740991."],
["limit=1&limit=2", "parameter 'limit' is invalid. use a value greater than 0"],
["limit=1&limit=2", "parameter 'limit' is invalid. use a value greater than 0."],
])("rejects invalid pagination input %s", async (query, message) => {
const response = await request(app).get(`/api/exercises?${query}`);
expect(response.status).toBe(400);
Expand Down
Loading