Speed up test suite by using local npm.js stub

This commit is contained in:
Michael Jackson 2019-08-01 18:01:12 -07:00
parent f362fa9717
commit c3dc2dd014
16 changed files with 89 additions and 71 deletions

View File

@ -3,9 +3,9 @@ module.exports = {
'\\.css$': '<rootDir>/modules/__mocks__/styleMock.js',
'\\.png$': '<rootDir>/modules/__mocks__/imageMock.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'],
testURL: 'http://localhost/',
setupTestFrameworkScriptFile: './jest.setup.js'
testURL: 'http://localhost/'
};

View File

@ -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);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -10,7 +10,7 @@ describe('A request for a JavaScript file', () => {
it('returns 200', done => {
request(server)
.get('/react@16.8.6/index.js')
.get('/react@16.8.0/index.js')
.end((err, res) => {
expect(res.statusCode).toBe(200);
expect(res.headers['content-type']).toMatch(

View File

@ -10,7 +10,7 @@ describe('A request for metadata', () => {
it('returns 200', done => {
request(server)
.get('/react@16.8.6/?meta')
.get('/react@16.8.0/?meta')
.end((err, res) => {
expect(res.statusCode).toBe(200);
expect(res.headers['content-type']).toMatch(/\bapplication\/json\b/);

View File

@ -1,11 +1,12 @@
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import semver from 'semver';
import BrowseApp from '../client/browse/App.js';
import MainTemplate from '../templates/MainTemplate.js';
import asyncHandler from '../utils/asyncHandler.js';
import getScripts from '../utils/getScripts.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 globalURLs =
@ -21,6 +22,15 @@ const globalURLs =
'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) {
const availableVersions = await getAvailableVersions(req.packageName);
const data = {

View File

@ -1,6 +1,8 @@
import semver from 'semver';
import asyncHandler from '../utils/asyncHandler.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) {
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
* fetch the package config and add it to req.packageConfig. Redirect to

View File

@ -1,7 +1,6 @@
import url from 'url';
import https from 'https';
import LRUCache from 'lru-cache';
import semver from 'semver';
import debug from './debug.js';
import bufferStream from './bufferStream.js';
@ -77,18 +76,16 @@ async function fetchPackageInfo(packageName) {
async function fetchVersionsAndTags(packageName) {
const info = await fetchPackageInfo(packageName);
if (info && info.versions) {
return {
versions: Object.keys(info.versions),
tags: info['dist-tags']
};
return info && info.versions
? { versions: Object.keys(info.versions), tags: info['dist-tags'] }
: null;
}
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 cacheValue = cache.get(cacheKey);
@ -107,45 +104,6 @@ async function getVersionsAndTags(packageName) {
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
// docs that we don't need. There are probably more.
const packageConfigExcludeKeys = [
@ -160,10 +118,10 @@ const packageConfigExcludeKeys = [
'scripts'
];
function cleanPackageConfig(doc) {
return Object.keys(doc).reduce((memo, key) => {
function cleanPackageConfig(config) {
return Object.keys(config).reduce((memo, key) => {
if (!key.startsWith('_') && !packageConfigExcludeKeys.includes(key)) {
memo[key] = doc[key];
memo[key] = config[key];
}
return memo;
@ -172,17 +130,14 @@ function cleanPackageConfig(doc) {
async function fetchPackageConfig(packageName, version) {
const info = await fetchPackageInfo(packageName);
if (!info || !(version in info.versions)) {
return null;
}
return cleanPackageConfig(info.versions[version]);
return info && info.versions && version in info.versions
? cleanPackageConfig(info.versions[version])
: null;
}
/**
* 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) {
const cacheKey = `config-${packageName}-${version}`;