Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/tests-ranges.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ name: "Test Suite: ranges"
on:
pull_request:
paths:
- 'ranges/*'
- 'ranges/**'
- 'core/**'
- 'aliases/**'
branches:
- main
workflow_dispatch:
Expand Down
4 changes: 2 additions & 2 deletions ranges/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"scripts": {
"lint": "biome check ./",
"lint:write": "biome check ./ --write",
"test": "node --test",
"coverage": "c8 node --test",
"test": "node --test test/*.test.js",
"coverage": "c8 node --test test/*.test.js",
"updates:check": "npx npm-check-updates",
"updates:update": "npx npm-check-updates -u"
},
Expand Down
15 changes: 3 additions & 12 deletions ranges/test/alpha.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { deepStrictEqual } = require('node:assert');
const ranges = require('../index');
const fixtures = require('./fixtures');
const { describe, it } = require('node:test');

// these tests use made-up data that follows the release schedule starting with
Expand Down Expand Up @@ -41,18 +42,8 @@ const schedule = {
},
};

// only serves the releases that would be out by `now`, like the real index.json
function at(now) {
return {
now,
fetch: async (url) =>
Response.json(
url.endsWith('schedule.json')
? schedule
: index.filter((entry) => entry.date <= now),
),
};
}
// serves the made-up data above instead of core's snapshots
const at = (now) => fixtures.at(now, { index, schedule });

describe('check to make sure that Alpha releases work as expected', async () => {
it('should leave Alpha releases out of "all"', async () => {
Expand Down
5 changes: 3 additions & 2 deletions ranges/test/default.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
const assert = require('node:assert');
const ranges = require('../index');
const { at } = require('./fixtures');
const { describe, it } = require('node:test');

describe('data should exist as it is defined', async () => {
it('versions should have correct types on every property', async () => {
const data = await ranges();
const data = await ranges(undefined, at());
for (const key in data) {
assert.deepStrictEqual(Array.isArray(data[key].versions), true);
assert.deepStrictEqual(data[key].versions.length > 0, true);
Expand All @@ -16,7 +17,7 @@ describe('data should exist as it is defined', async () => {
});

it('both newest and oldest on every property should be the correct type', async () => {
const data = await ranges();
const data = await ranges(undefined, at());
for (const key in data) {
assert.deepStrictEqual(typeof data[key].newest, 'string');
assert.deepStrictEqual(typeof data[key].oldest, 'string');
Expand Down
31 changes: 31 additions & 0 deletions ranges/test/fixtures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const index = require('../../core/test/data/static/index.json');
const schedule = require('../../core/test/data/static/schedule.json');

// the default date for tests. on 2025-09-01, v24 is Current, v22 is Active
// LTS, v20 is Maintenance LTS, and v23 has reached End of Life, so every
// range has versions. every one of those lines also has a security release
// by then, so no security field is empty either.
const now = '2025-09-01';

// returns options for `ranges` that serve `data` (core's index.json and
// schedule.json snapshots by default) instead of fetching them, only including
// releases that would be out by `now`, like the real index.json. any other URL
// throws, so tests never touch the network.
function at(date = now, data = { index, schedule }) {
return {
now: date,
fetch: async (url) => {
if (url.endsWith('/schedule.json')) {
return Response.json(data.schedule);
}

if (url.endsWith('/index.json')) {
return Response.json(data.index.filter((entry) => entry.date <= date));
}

throw new Error(`No fixture data for ${url}`);
},
};
}

module.exports = { at };
60 changes: 58 additions & 2 deletions ranges/test/known.test.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,74 @@
const assert = require('node:assert');
const ranges = require('../index');
const { at } = require('./fixtures');
const { describe, it } = require('node:test');

describe('check some values we know should exist', async () => {
it('should include some known, static values in "all"', async () => {
const data = await ranges();
const data = await ranges(undefined, at());
assert.deepStrictEqual(data.all.versions.includes('v19.0.0'), true); // a semver major we know exists
assert.deepStrictEqual(data.all.versions.includes('v14.21.0'), true); // an LTS release we know happened
assert.deepStrictEqual(data.all.versions.includes('v0.1.14'), true); // oldest included data in the array - this is the correct oldest data since it's technically the first entry on nodejs.org/dist/index.json
});

it('should include some known, static values in "eol"', async () => {
const data = await ranges();
const data = await ranges(undefined, at());
assert.deepStrictEqual(data.all.versions.includes('v14.21.0'), true); // an LTS release we know happened
assert.deepStrictEqual(data.eol.versions.includes('v0.8.0'), true); // oldest included data in the array - this should be fixed since it's clearly not the oldest in the dataset.
});

// on 2025-09-01, v24 is Current, v22 is Active LTS, v20 is Maintenance LTS,
// and v23 is the newest End of Life line
it('should put each release line in the right range', async () => {
const data = await ranges(undefined, at());
const summary = Object.fromEntries(
Object.entries(data).map(([alias, { versions, ...range }]) => [
alias,
range,
]),
);

assert.deepStrictEqual(summary, {
all: {
newestLts: 'v22.19.0',
newestSecurity: 'v24.4.1',
newest: 'v24.7.0',
oldest: 'v0.1.14',
},
current: {
oldestSecurity: '24.0.2',
newestSecurity: '24.4.1',
newest: 'v24.7.0',
oldest: 'v24.0.0',
},
'lts/latest': {
oldestLts: '22.11.0',
oldestSecurity: '22.4.1',
newestLts: '22.19.0',
newestSecurity: '22.17.1',
newest: 'v22.19.0',
oldest: 'v22.11.0',
},
'lts/active': {
oldestLts: '20.9.0',
oldestSecurity: '20.3.1',
newestLts: '22.19.0',
newestSecurity: '22.17.1',
newest: 'v22.19.0',
oldest: 'v20.9.0',
},
'lts/maintenance': {
oldestLts: '20.9.0',
oldestSecurity: '20.3.1',
newestLts: '20.19.4',
newestSecurity: '20.19.4',
newest: 'v20.19.4',
oldest: 'v20.9.0',
},
eol: {
newest: 'v23.11.1',
oldest: 'v0.8.0',
},
});
});
});
34 changes: 21 additions & 13 deletions ranges/test/matrixAlias.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const assert = require('node:assert');
const ranges = require('../index');
const { at } = require('./fixtures');
const { describe, it } = require('node:test');

// this is a non-exhaustive list of sets of aliases.
// please feel free to add more.
describe('data should exist as it is defined when calling multiple aliases', async () => {
// begin by testing some of the more risky logic in the data construction
it('versions should have correct types on every property if an array when "lts/latest" and "lts/maintenance" are passed', async () => {
const data = await ranges(['lts/latest', 'lts/maintenance']);
const data = await ranges(['lts/latest', 'lts/maintenance'], at());

// check lts/latest values
assert.deepStrictEqual(Array.isArray(data['lts/latest'].versions), true);
Expand Down Expand Up @@ -37,7 +38,7 @@ describe('data should exist as it is defined when calling multiple aliases', asy
});

it('versions should have correct types on every property if an array when "lts/latest" and "lts/active" are passed', async () => {
const data = await ranges(['lts/latest', 'lts/active']);
const data = await ranges(['lts/latest', 'lts/active'], at());

// check lts/latest values
assert.deepStrictEqual(Array.isArray(data['lts/latest'].versions), true);
Expand All @@ -64,7 +65,7 @@ describe('data should exist as it is defined when calling multiple aliases', asy
});

it('versions should have correct types on every property if an array when "lts/maintenance" and "lts/active" are passed', async () => {
const data = await ranges(['lts/maintenance', 'lts/active']);
const data = await ranges(['lts/maintenance', 'lts/active'], at());

// check lts/maintenance values
assert.deepStrictEqual(
Expand Down Expand Up @@ -94,7 +95,10 @@ describe('data should exist as it is defined when calling multiple aliases', asy
});

it('versions should have correct types on every property if an array when "lts/maintenance", "lts/active", and "lts/latest" are passed', async () => {
const data = await ranges(['lts/maintenance', 'lts/active', 'lts/latest']);
const data = await ranges(
['lts/maintenance', 'lts/active', 'lts/latest'],
at(),
);

// check lts/maintenance values
assert.deepStrictEqual(
Expand Down Expand Up @@ -138,7 +142,7 @@ describe('data should exist as it is defined when calling multiple aliases', asy
// we want to make sure that we're specifically testing the translations
// as a set to ensure that it is direct and clear when they're breaking.
it('should pass the "lts" translation ("lts/active" and "lts/maintenance")', async () => {
const data = await ranges(['lts/active', 'lts/maintenance']);
const data = await ranges(['lts/active', 'lts/maintenance'], at());

// check lts/active values
assert.deepStrictEqual(Array.isArray(data['lts/active'].versions), true);
Expand Down Expand Up @@ -171,7 +175,10 @@ describe('data should exist as it is defined when calling multiple aliases', asy
});

it('should pass the "supported" translation ("current", "lts/active", and "lts/maintenance")', async () => {
const data = await ranges(['current', 'lts/active', 'lts/maintenance']);
const data = await ranges(
['current', 'lts/active', 'lts/maintenance'],
at(),
);

// check current values
assert.deepStrictEqual(Array.isArray(data.current.versions), true);
Expand Down Expand Up @@ -211,7 +218,10 @@ describe('data should exist as it is defined when calling multiple aliases', asy
});

it('should pass the "supported" translation ("current", "lts/active", and "lts/maintenance")', async () => {
const data = await ranges(['current', 'lts/active', 'lts/maintenance']);
const data = await ranges(
['current', 'lts/active', 'lts/maintenance'],
at(),
);

// check current values
assert.deepStrictEqual(Array.isArray(data.current.versions), true);
Expand Down Expand Up @@ -251,12 +261,10 @@ describe('data should exist as it is defined when calling multiple aliases', asy
});

it('should pass the "all" translation ("current", "lts/active", "lts/maintenance", and "eol")', async () => {
const data = await ranges([
'current',
'lts/active',
'lts/maintenance',
'eol',
]);
const data = await ranges(
['current', 'lts/active', 'lts/maintenance', 'eol'],
at(),
);

// check current values
assert.deepStrictEqual(Array.isArray(data.current.versions), true);
Expand Down
13 changes: 7 additions & 6 deletions ranges/test/singleAlias.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
const assert = require('node:assert');
const ranges = require('../index');
const { at } = require('./fixtures');
const { describe, it } = require('node:test');

describe('data should exist as it is defined when calling a single alias', async () => {
it('versions should have correct types on every property if an array with "all" is passed', async () => {
const data = await ranges(['all']);
const data = await ranges(['all'], at());
assert.deepStrictEqual(Array.isArray(data.all.versions), true);
assert.deepStrictEqual(data.all.versions.length > 0, true);
assert.deepStrictEqual(
Expand All @@ -14,7 +15,7 @@ describe('data should exist as it is defined when calling a single alias', async
});

it('versions should have correct types on every property if an array with "current" is passed', async () => {
const data = await ranges(['current']);
const data = await ranges(['current'], at());
assert.deepStrictEqual(Array.isArray(data.current.versions), true);
assert.deepStrictEqual(data.current.versions.length > 0, true);
assert.deepStrictEqual(
Expand All @@ -24,7 +25,7 @@ describe('data should exist as it is defined when calling a single alias', async
});

it('versions should have correct types on every property if an array with "lts/latest" is passed', async () => {
const data = await ranges(['lts/latest']);
const data = await ranges(['lts/latest'], at());
assert.deepStrictEqual(Array.isArray(data['lts/latest'].versions), true);
assert.deepStrictEqual(data['lts/latest'].versions.length > 0, true);
assert.deepStrictEqual(
Expand All @@ -40,7 +41,7 @@ describe('data should exist as it is defined when calling a single alias', async
});

it('versions should have correct types on every property if an array with "lts/active" is passed', async () => {
const data = await ranges(['lts/active']);
const data = await ranges(['lts/active'], at());
assert.deepStrictEqual(Array.isArray(data['lts/active'].versions), true);
assert.deepStrictEqual(data['lts/active'].versions.length > 0, true);
assert.deepStrictEqual(
Expand All @@ -56,7 +57,7 @@ describe('data should exist as it is defined when calling a single alias', async
});

it('versions should have correct types on every property if an array with "lts/maintenance" is passed', async () => {
const data = await ranges(['lts/maintenance']);
const data = await ranges(['lts/maintenance'], at());
assert.deepStrictEqual(
Array.isArray(data['lts/maintenance'].versions),
true,
Expand All @@ -75,7 +76,7 @@ describe('data should exist as it is defined when calling a single alias', async
});

it('versions should have correct types on every property if an array with "eol" is passed', async () => {
const data = await ranges(['eol']);
const data = await ranges(['eol'], at());
assert.deepStrictEqual(Array.isArray(data.eol.versions), true);
assert.deepStrictEqual(data.eol.versions.length > 0, true);
assert.deepStrictEqual(
Expand Down
13 changes: 7 additions & 6 deletions ranges/test/unknownFilter.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
const assert = require('node:assert');
const ranges = require('../index');
const { at } = require('./fixtures');
const { describe, it } = require('node:test');

describe('failure states for arguments', async () => {
it('should throw an error on a string with an unknown value', async () => {
try {
const data = await ranges('poopin');
const data = await ranges('poopin', at());
if (data) throw new Error('Should not have gotten here');
} catch (error) {
assert.deepStrictEqual(
Expand All @@ -17,7 +18,7 @@ describe('failure states for arguments', async () => {

it('should throw an error on a string with an unknown value', async () => {
try {
const data = await ranges('poopin');
const data = await ranges('poopin', at());
if (data) throw new Error('Should not have gotten here');
} catch (error) {
assert.deepStrictEqual(
Expand All @@ -29,7 +30,7 @@ describe('failure states for arguments', async () => {

it('should throw an error on a single unknown array entry', async () => {
try {
const data = await ranges(['poopin']);
const data = await ranges(['poopin'], at());
if (data) throw new Error('Should not have gotten here');
} catch (error) {
assert.deepStrictEqual(
Expand All @@ -41,7 +42,7 @@ describe('failure states for arguments', async () => {

it('should throw an error on an unknown array entry where multiple entries exist and it is the first entry', async () => {
try {
const data = await ranges(['poopin', 'lts/active']);
const data = await ranges(['poopin', 'lts/active'], at());
if (data) throw new Error('Should not have gotten here');
} catch (error) {
assert.deepStrictEqual(
Expand All @@ -53,7 +54,7 @@ describe('failure states for arguments', async () => {

it('should throw an error on an unknown array entry where multiple entries exist and it is the first entry', async () => {
try {
const data = await ranges(['lts/active', 'poopin']);
const data = await ranges(['lts/active', 'poopin'], at());
if (data) throw new Error('Should not have gotten here');
} catch (error) {
assert.deepStrictEqual(
Expand All @@ -65,7 +66,7 @@ describe('failure states for arguments', async () => {

it('should throw an error on passing an Object', async () => {
try {
const data = await ranges({});
const data = await ranges({}, at());
if (data) throw new Error('Should not have gotten here');
} catch (error) {
assert.deepStrictEqual(
Expand Down
Loading
Loading