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
9 changes: 9 additions & 0 deletions .c8rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"all": true,
"exclude": ["coverage/**", "test/**"],
"check-coverage": true,
"branches": 100,
"functions": 100,
"lines": 100,
"statements": 100
}
4 changes: 2 additions & 2 deletions .github/workflows/tests-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w core
run: npm install -w core
- name: Run npm test -w core
run: npm test -w core
- name: Run npm run coverage -w core
run: npm run coverage -w core
4 changes: 2 additions & 2 deletions .github/workflows/tests-fetchindex.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w fetchindex
run: npm install -w fetchindex
- name: Run npm test -w fetchindex
run: npm test -w fetchindex
- name: Run npm run coverage -w fetchindex
run: npm run coverage -w fetchindex
4 changes: 2 additions & 2 deletions .github/workflows/tests-newest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w newest
run: npm install -w newest
- name: Run npm test -w newest
run: npm test -w newest
- name: Run npm run coverage -w newest
run: npm run coverage -w newest
4 changes: 2 additions & 2 deletions .github/workflows/tests-oldest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w oldest
run: npm install -w oldest
- name: Run npm test -w oldest
run: npm test -w oldest
- name: Run npm run coverage -w oldest
run: npm run coverage -w oldest
4 changes: 2 additions & 2 deletions .github/workflows/tests-opt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w opt
run: npm install -w opt
- name: Run npm test -w opt
run: npm test -w opt
- name: Run npm run coverage -w opt
run: npm run coverage -w opt
4 changes: 2 additions & 2 deletions .github/workflows/tests-parsefiles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w parsefiles
run: npm install -w parsefiles
- name: Run npm test -w parsefiles
run: npm test -w parsefiles
- name: Run npm run coverage -w parsefiles
run: npm run coverage -w parsefiles
4 changes: 2 additions & 2 deletions .github/workflows/tests-ranges.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w ranges
run: npm install -w ranges
- name: Run npm test -w ranges
run: npm test -w ranges
- name: Run npm run coverage -w ranges
run: npm run coverage -w ranges
4 changes: 2 additions & 2 deletions .github/workflows/tests-static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w static
run: npm install -w static
- name: Run npm test -w static
run: npm test -w static
- name: Run npm run coverage -w static
run: npm run coverage -w static
4 changes: 2 additions & 2 deletions .github/workflows/tests-translate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ jobs:
run: npm install -g npm
- name: Run npm install -w translate
run: npm install -w translate
- name: Run npm test -w translate
run: npm test -w translate
- name: Run npm run coverage -w translate
run: npm run coverage -w translate
24 changes: 9 additions & 15 deletions core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async function core(options) {

// TODO: parse versions[version].files and convert them to URLs that can be directly accessed
data[name].releases[`v${versionSemver.version}`].files.available =
versions[version].files ?? undefined;
versions[version].files ?? [];

const availableShorthand =
data[name].releases[`v${versionSemver.version}`].files.available; // since we're going to be writing this a lot for assignments, it's nice to have shorthand for readability
Expand Down Expand Up @@ -209,24 +209,18 @@ async function core(options) {
}

function determineCurrentReleasePhase(now, dates = {}) {
// we set set this up to enable custom `now` passing, since passing an ISO
// const usableNow = DateTime.fromISO(now)

// here we figure out if the dates for each release line passed is in the past or future
// `true` is in the past
// `false` is in the future
// `undefined` is a missing date
const isoified = {
alpha:
isInPast(DateTime.fromISO(dates.alpha).diff(now).toMillis()) ?? undefined,
start:
isInPast(DateTime.fromISO(dates.start).diff(now).toMillis()) ?? undefined,
lts:
isInPast(DateTime.fromISO(dates.lts).diff(now).toMillis()) ?? undefined,
maintenance:
isInPast(DateTime.fromISO(dates.maintenance).diff(now).toMillis()) ??
undefined,
end:
isInPast(DateTime.fromISO(dates.end).diff(now).toMillis()) ?? undefined,
alpha: isInPast(DateTime.fromISO(dates.alpha).diff(now).toMillis()),
start: isInPast(DateTime.fromISO(dates.start).diff(now).toMillis()),
lts: isInPast(DateTime.fromISO(dates.lts).diff(now).toMillis()),
maintenance: isInPast(
DateTime.fromISO(dates.maintenance).diff(now).toMillis(),
),
end: isInPast(DateTime.fromISO(dates.end).diff(now).toMillis()),
};

// set up our result to return
Expand Down
1 change: 1 addition & 0 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
},
"devDependencies": {
"c8": "^10.1.2",
"fast-check": "^4.10.2",
"undici": "^6.20.1"
},
"repository": {
Expand Down
4 changes: 1 addition & 3 deletions core/test/combos.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ function check(data) {
assert.deepStrictEqual(data.v12.security.oldest, '12.8.1');
}

const staticNow = require('./data/static/now.json');

const now = JSON.parse(staticNow);
const now = require('./data/static/now.json');

describe('check to make sure that combining options works as expected', async () => {
beforeEach(beforeEachTemplate);
Expand Down
2 changes: 1 addition & 1 deletion core/test/data/static/now.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"\"2025-10-30T08:51:04.858-07:00\""
"2025-10-30T08:51:04.858-07:00"
84 changes: 84 additions & 0 deletions core/test/dev-fixtures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const assert = require('node:assert');
const { describe, it } = require('node:test');
const fc = require('fast-check');
const { at } = require('../util/dev/fixtures');
const schedule = require('./data/static/schedule.json');

describe('at', async () => {
it('should pass now through as an option', () => {
// Arrange
const now = '2025-09-01';

// Act
const options = at(now);

// Assert
assert.strictEqual(options.now, now);
});

it("should serve core's schedule.json snapshot by default", async () => {
// Arrange
const { fetch } = at('2025-09-01');

// Act
const response = await fetch(
'https://raw.githubusercontent.com/nodejs/Release/master/schedule.json',
);

// Assert
assert.deepStrictEqual(await response.json(), schedule);
});

it('should only serve the releases that were out by now', async () => {
// Arrange
const index = [
{ version: 'v24.8.0', date: '2025-09-10' },
{ version: 'v24.7.0', date: '2025-08-27' },
];

const { fetch } = at('2025-09-01', { index, schedule: {} });

// Act
const response = await fetch('https://nodejs.org/dist/index.json');

// Assert
assert.deepStrictEqual(await response.json(), [
{ version: 'v24.7.0', date: '2025-08-27' },
]);
});

it('should throw for any other URL', async () => {
// Arrange
const { fetch } = at('2025-09-01');

// Act
const response = fetch('https://nodejs.org/dist/v24.7.0/SHASUMS256.txt');

// Assert
await assert.rejects(response, /No fixture data/);
});

it('should never serve a release from after now', async () => {
await fc.assert(
fc.asyncProperty(
fc.date({
min: new Date('2009-01-01'),
max: new Date('2100-01-01'),
noInvalidDate: true,
}),
async (date) => {
// Arrange
const now = date.toISOString().slice(0, 10);
const { fetch } = at(now);

// Act
const response = await fetch('https://nodejs.org/dist/index.json');

// Assert
const releases = await response.json();
assert.ok(releases.every((release) => release.date <= now));
},
),
);
});
});
80 changes: 80 additions & 0 deletions core/test/dev-scripts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const assert = require('node:assert');
const { execFile } = require('node:child_process');
const { mkdir, mkdtemp, readFile } = require('node:fs/promises');
const { tmpdir } = require('node:os');
const { join } = require('node:path');
const { describe, it } = require('node:test');
const { promisify } = require('node:util');
const { DateTime } = require('luxon');
const index = require('./data/static/index.json');
const schedule = require('./data/static/schedule.json');

describe('test:update:static', async () => {
it('should save the index.json and schedule.json it downloads', async () => {
// Arrange
const cwd = await snapshotDirectory();

// Act
await runScript(
'updateStaticData.js',
`require(${JSON.stringify(require.resolve('../util/dev/beforeEachTemplate'))})();`,
cwd,
);

// Assert
assert.deepStrictEqual(
{
index: await readSnapshot(cwd, 'index.json'),
schedule: await readSnapshot(cwd, 'schedule.json'),
},
{ index, schedule },
);
});
});

describe('test:update:now', async () => {
it('should save the current time as an ISO string', async () => {
// Arrange
const cwd = await snapshotDirectory();
const now = Date.parse('2025-10-30T15:51:04.858Z');

// Act
await runScript(
'updateStaticNow.js',
`require(${JSON.stringify(require.resolve('luxon'))}).Settings.now = () => ${now};`,
cwd,
);

// Assert
const saved = await readSnapshot(cwd, 'now.json');
assert.strictEqual(DateTime.fromISO(saved).toMillis(), now);
});
});

// Helpers

// a directory laid out like core, for the scripts to write their snapshots into
async function snapshotDirectory() {
const cwd = await mkdtemp(join(tmpdir(), 'nodevu-'));
await mkdir(join(cwd, 'test/data/static'), { recursive: true });

return cwd;
}

async function readSnapshot(cwd, file) {
return JSON.parse(
await readFile(join(cwd, 'test/data/static', file), 'utf8'),
);
}

// runs a util/dev script the way its npm script does, after `setup` stubs
// whatever it reaches outside the process for
function runScript(script, setup, cwd) {
const path = require.resolve(`../util/dev/${script}`);

return promisify(execFile)(
process.execPath,
['-e', `${setup} require(${JSON.stringify(path)});`],
{ cwd },
);
}
22 changes: 22 additions & 0 deletions core/test/dev-write.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const assert = require('node:assert');
const { mkdtemp, readFile } = require('node:fs/promises');
const { tmpdir } = require('node:os');
const { join } = require('node:path');
const { describe, it } = require('node:test');
const write = require('../util/dev/write');

describe('write', async () => {
it('should save data as tab-indented JSON', async () => {
// Arrange
const path = join(await mkdtemp(join(tmpdir(), 'nodevu-')), 'data.json');

// Act
await write(path, { v22: { codename: 'Jod' } });

// Assert
assert.strictEqual(
await readFile(path, 'utf8'),
'{\n\t"v22": {\n\t\t"codename": "Jod"\n\t}\n}',
);
});
});
4 changes: 1 addition & 3 deletions core/test/dynamic-values.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ const { describe, it, beforeEach } = require('node:test');

const beforeEachTemplate = require('../util/dev/beforeEachTemplate');

const staticNow = require('./data/static/now.json');

const now = JSON.parse(staticNow);
const now = require('./data/static/now.json');

// this is a set of tests that only test against static data effectively frozen at a point in time.
// these tests should *probably* be updated sometimes. see the npm scripts for update scripts.
Expand Down
22 changes: 22 additions & 0 deletions core/test/files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const assert = require('node:assert');
const { describe, it } = require('node:test');
const nodevu = require('../index');

describe('files for a release that index.json lists without any', async () => {
it('should return no available files and no links', async () => {
const data = await nodevu({
fetch: async (url) =>
Response.json(
url.endsWith('schedule.json')
? {}
: [{ version: 'v28.0.0', date: '2028-01-01', lts: false }],
),
now: '2028-01-01',
});

assert.deepStrictEqual(data.v28.releases['v28.0.0'].files, {
available: [],
links: {},
});
});
});
Loading
Loading