Speed up test suite by using local npm.js stub
This commit is contained in:
@ -3,9 +3,9 @@ module.exports = {
|
|||||||
'\\.css$': '<rootDir>/modules/__mocks__/styleMock.js',
|
'\\.css$': '<rootDir>/modules/__mocks__/styleMock.js',
|
||||||
'\\.png$': '<rootDir>/modules/__mocks__/imageMock.js',
|
'\\.png$': '<rootDir>/modules/__mocks__/imageMock.js',
|
||||||
'entry-manifest': '<rootDir>/modules/__mocks__/entryManifest.js',
|
'entry-manifest': '<rootDir>/modules/__mocks__/entryManifest.js',
|
||||||
'getStats\\.js': '<rootDir>/modules/__mocks__/getStatsMock.js'
|
'getStats\\.js': '<rootDir>/modules/__mocks__/getStatsMock.js',
|
||||||
|
'utils\\/npm\\.js': '<rootDir>/modules/__mocks__/npmMock.js'
|
||||||
},
|
},
|
||||||
testMatch: ['**/__tests__/*-test.js'],
|
testMatch: ['**/__tests__/*-test.js'],
|
||||||
testURL: 'http://localhost/',
|
testURL: 'http://localhost/'
|
||||||
setupTestFrameworkScriptFile: './jest.setup.js'
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
// TODO: Mock out the registry so tests don't actually hit
|
|
||||||
// the real registry so they don't take so long. Then we can
|
|
||||||
// remove this.
|
|
||||||
jest.setTimeout(10000);
|
|
||||||
1
modules/__mocks__/metadata/@babel/core.json
Normal file
1
modules/__mocks__/metadata/@babel/core.json
Normal file
File diff suppressed because one or more lines are too long
1
modules/__mocks__/metadata/preact.json
Normal file
1
modules/__mocks__/metadata/preact.json
Normal file
File diff suppressed because one or more lines are too long
1
modules/__mocks__/metadata/react.json
Normal file
1
modules/__mocks__/metadata/react.json
Normal file
File diff suppressed because one or more lines are too long
1
modules/__mocks__/metadata/sinuous.json
Normal file
1
modules/__mocks__/metadata/sinuous.json
Normal file
File diff suppressed because one or more lines are too long
33
modules/__mocks__/npmMock.js
Normal file
33
modules/__mocks__/npmMock.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
function getPackageInfo(packageName) {
|
||||||
|
const file = path.resolve(__dirname, `./metadata/${packageName}.json`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVersionsAndTags(packageName) {
|
||||||
|
const info = getPackageInfo(packageName);
|
||||||
|
return info
|
||||||
|
? { versions: Object.keys(info.versions), tags: info['dist-tags'] }
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPackageConfig(packageName, version) {
|
||||||
|
const info = getPackageInfo(packageName);
|
||||||
|
return info ? info.versions[version] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPackage(packageName, version) {
|
||||||
|
const file = path.resolve(
|
||||||
|
__dirname,
|
||||||
|
`./packages/${packageName}-${version}.tgz`
|
||||||
|
);
|
||||||
|
|
||||||
|
return fs.existsSync(file) ? fs.createReadStream(file) : null;
|
||||||
|
}
|
||||||
BIN
modules/__mocks__/packages/@babel/core-7.5.4.tgz
Normal file
BIN
modules/__mocks__/packages/@babel/core-7.5.4.tgz
Normal file
Binary file not shown.
BIN
modules/__mocks__/packages/preact-8.4.2.tgz
Normal file
BIN
modules/__mocks__/packages/preact-8.4.2.tgz
Normal file
Binary file not shown.
BIN
modules/__mocks__/packages/react-16.8.0.tgz
Normal file
BIN
modules/__mocks__/packages/react-16.8.0.tgz
Normal file
Binary file not shown.
BIN
modules/__mocks__/packages/sinuous-0.12.9.tgz
Normal file
BIN
modules/__mocks__/packages/sinuous-0.12.9.tgz
Normal file
Binary file not shown.
@ -10,7 +10,7 @@ describe('A request for a JavaScript file', () => {
|
|||||||
|
|
||||||
it('returns 200', done => {
|
it('returns 200', done => {
|
||||||
request(server)
|
request(server)
|
||||||
.get('/react@16.8.6/index.js')
|
.get('/react@16.8.0/index.js')
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
expect(res.headers['content-type']).toMatch(
|
expect(res.headers['content-type']).toMatch(
|
||||||
|
|||||||
@ -10,7 +10,7 @@ describe('A request for metadata', () => {
|
|||||||
|
|
||||||
it('returns 200', done => {
|
it('returns 200', done => {
|
||||||
request(server)
|
request(server)
|
||||||
.get('/react@16.8.6/?meta')
|
.get('/react@16.8.0/?meta')
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
expect(res.headers['content-type']).toMatch(/\bapplication\/json\b/);
|
expect(res.headers['content-type']).toMatch(/\bapplication\/json\b/);
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
|
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
|
||||||
|
import semver from 'semver';
|
||||||
|
|
||||||
import BrowseApp from '../client/browse/App.js';
|
import BrowseApp from '../client/browse/App.js';
|
||||||
import MainTemplate from '../templates/MainTemplate.js';
|
import MainTemplate from '../templates/MainTemplate.js';
|
||||||
import asyncHandler from '../utils/asyncHandler.js';
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import getScripts from '../utils/getScripts.js';
|
import getScripts from '../utils/getScripts.js';
|
||||||
import { createElement, createHTML } from '../utils/markup.js';
|
import { createElement, createHTML } from '../utils/markup.js';
|
||||||
import { getAvailableVersions } from '../utils/npm.js';
|
import { getVersionsAndTags } from '../utils/npm.js';
|
||||||
|
|
||||||
const doctype = '<!DOCTYPE html>';
|
const doctype = '<!DOCTYPE html>';
|
||||||
const globalURLs =
|
const globalURLs =
|
||||||
@ -21,6 +22,15 @@ const globalURLs =
|
|||||||
'react-dom': '/react-dom@16.8.6/umd/react-dom.development.js'
|
'react-dom': '/react-dom@16.8.6/umd/react-dom.development.js'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function byVersion(a, b) {
|
||||||
|
return semver.lt(a, b) ? -1 : semver.gt(a, b) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAvailableVersions(packageName) {
|
||||||
|
const versionsAndTags = await getVersionsAndTags(packageName);
|
||||||
|
return versionsAndTags ? versionsAndTags.versions.sort(byVersion) : [];
|
||||||
|
}
|
||||||
|
|
||||||
async function serveBrowsePage(req, res) {
|
async function serveBrowsePage(req, res) {
|
||||||
const availableVersions = await getAvailableVersions(req.packageName);
|
const availableVersions = await getAvailableVersions(req.packageName);
|
||||||
const data = {
|
const data = {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import semver from 'semver';
|
||||||
|
|
||||||
import asyncHandler from '../utils/asyncHandler.js';
|
import asyncHandler from '../utils/asyncHandler.js';
|
||||||
import createPackageURL from '../utils/createPackageURL.js';
|
import createPackageURL from '../utils/createPackageURL.js';
|
||||||
import { getPackageConfig, resolveVersion } from '../utils/npm.js';
|
import { getPackageConfig, getVersionsAndTags } from '../utils/npm.js';
|
||||||
|
|
||||||
function semverRedirect(req, res, newVersion) {
|
function semverRedirect(req, res, newVersion) {
|
||||||
res
|
res
|
||||||
@ -15,6 +17,24 @@ function semverRedirect(req, res, newVersion) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resolveVersion(packageName, range) {
|
||||||
|
const versionsAndTags = await getVersionsAndTags(packageName);
|
||||||
|
|
||||||
|
if (versionsAndTags) {
|
||||||
|
const { versions, tags } = versionsAndTags;
|
||||||
|
|
||||||
|
if (range in tags) {
|
||||||
|
range = tags[range];
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions.includes(range)
|
||||||
|
? range
|
||||||
|
: semver.maxSatisfying(versions, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the package version/tag in the URL and make sure it's good. Also
|
* Check the package version/tag in the URL and make sure it's good. Also
|
||||||
* fetch the package config and add it to req.packageConfig. Redirect to
|
* fetch the package config and add it to req.packageConfig. Redirect to
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import url from 'url';
|
import url from 'url';
|
||||||
import https from 'https';
|
import https from 'https';
|
||||||
import LRUCache from 'lru-cache';
|
import LRUCache from 'lru-cache';
|
||||||
import semver from 'semver';
|
|
||||||
|
|
||||||
import debug from './debug.js';
|
import debug from './debug.js';
|
||||||
import bufferStream from './bufferStream.js';
|
import bufferStream from './bufferStream.js';
|
||||||
@ -77,18 +76,16 @@ async function fetchPackageInfo(packageName) {
|
|||||||
|
|
||||||
async function fetchVersionsAndTags(packageName) {
|
async function fetchVersionsAndTags(packageName) {
|
||||||
const info = await fetchPackageInfo(packageName);
|
const info = await fetchPackageInfo(packageName);
|
||||||
|
return info && info.versions
|
||||||
if (info && info.versions) {
|
? { versions: Object.keys(info.versions), tags: info['dist-tags'] }
|
||||||
return {
|
: null;
|
||||||
versions: Object.keys(info.versions),
|
|
||||||
tags: info['dist-tags']
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVersionsAndTags(packageName) {
|
/**
|
||||||
|
* Returns an object of available { versions, tags }.
|
||||||
|
* Uses a cache to avoid over-fetching from the registry.
|
||||||
|
*/
|
||||||
|
export async function getVersionsAndTags(packageName) {
|
||||||
const cacheKey = `versions-${packageName}`;
|
const cacheKey = `versions-${packageName}`;
|
||||||
const cacheValue = cache.get(cacheKey);
|
const cacheValue = cache.get(cacheKey);
|
||||||
|
|
||||||
@ -107,45 +104,6 @@ async function getVersionsAndTags(packageName) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function byVersion(a, b) {
|
|
||||||
return semver.lt(a, b) ? -1 : semver.gt(a, b) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of available versions, sorted by semver.
|
|
||||||
*/
|
|
||||||
export async function getAvailableVersions(packageName) {
|
|
||||||
const versionsAndTags = await getVersionsAndTags(packageName);
|
|
||||||
|
|
||||||
if (versionsAndTags) {
|
|
||||||
return versionsAndTags.versions.sort(byVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the semver range or tag to a valid version.
|
|
||||||
* Output is cached to avoid over-fetching from the registry.
|
|
||||||
*/
|
|
||||||
export async function resolveVersion(packageName, range) {
|
|
||||||
const versionsAndTags = await getVersionsAndTags(packageName);
|
|
||||||
|
|
||||||
if (versionsAndTags) {
|
|
||||||
const { versions, tags } = versionsAndTags;
|
|
||||||
|
|
||||||
if (range in tags) {
|
|
||||||
range = tags[range];
|
|
||||||
}
|
|
||||||
|
|
||||||
return versions.includes(range)
|
|
||||||
? range
|
|
||||||
: semver.maxSatisfying(versions, range);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All the keys that sometimes appear in package info
|
// All the keys that sometimes appear in package info
|
||||||
// docs that we don't need. There are probably more.
|
// docs that we don't need. There are probably more.
|
||||||
const packageConfigExcludeKeys = [
|
const packageConfigExcludeKeys = [
|
||||||
@ -160,10 +118,10 @@ const packageConfigExcludeKeys = [
|
|||||||
'scripts'
|
'scripts'
|
||||||
];
|
];
|
||||||
|
|
||||||
function cleanPackageConfig(doc) {
|
function cleanPackageConfig(config) {
|
||||||
return Object.keys(doc).reduce((memo, key) => {
|
return Object.keys(config).reduce((memo, key) => {
|
||||||
if (!key.startsWith('_') && !packageConfigExcludeKeys.includes(key)) {
|
if (!key.startsWith('_') && !packageConfigExcludeKeys.includes(key)) {
|
||||||
memo[key] = doc[key];
|
memo[key] = config[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
return memo;
|
return memo;
|
||||||
@ -172,17 +130,14 @@ function cleanPackageConfig(doc) {
|
|||||||
|
|
||||||
async function fetchPackageConfig(packageName, version) {
|
async function fetchPackageConfig(packageName, version) {
|
||||||
const info = await fetchPackageInfo(packageName);
|
const info = await fetchPackageInfo(packageName);
|
||||||
|
return info && info.versions && version in info.versions
|
||||||
if (!info || !(version in info.versions)) {
|
? cleanPackageConfig(info.versions[version])
|
||||||
return null;
|
: null;
|
||||||
}
|
|
||||||
|
|
||||||
return cleanPackageConfig(info.versions[version]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns metadata about a package, mostly the same as package.json.
|
* Returns metadata about a package, mostly the same as package.json.
|
||||||
* Output is cached to avoid over-fetching from the registry.
|
* Uses a cache to avoid over-fetching from the registry.
|
||||||
*/
|
*/
|
||||||
export async function getPackageConfig(packageName, version) {
|
export async function getPackageConfig(packageName, version) {
|
||||||
const cacheKey = `config-${packageName}-${version}`;
|
const cacheKey = `config-${packageName}-${version}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user