const path = require('path'); const fs = require('fs-extra'); const assert = require('assert'); const { createZip } = require('../dist/lambda'); const { glob, spawnAsync, download } = require('../'); const { getSupportedNodeVersion } = require('../dist/fs/node-version'); const { getNodeVersion, getLatestNodeVersion, getDiscontinuedNodeVersions, } = require('../dist'); it('should re-create symlinks properly', async () => { if (process.platform === 'win32') { console.log('Skipping test on windows'); return; } const files = await glob('**', path.join(__dirname, 'symlinks')); assert.equal(Object.keys(files).length, 2); const outDir = path.join(__dirname, 'symlinks-out'); await fs.remove(outDir); const files2 = await download(files, outDir); assert.equal(Object.keys(files2).length, 2); const [linkStat, aStat] = await Promise.all([ fs.lstat(path.join(outDir, 'link.txt')), fs.lstat(path.join(outDir, 'a.txt')), ]); assert(linkStat.isSymbolicLink()); assert(aStat.isFile()); }); it('should create zip files with symlinks properly', async () => { if (process.platform === 'win32') { console.log('Skipping test on windows'); return; } const files = await glob('**', path.join(__dirname, 'symlinks')); assert.equal(Object.keys(files).length, 2); const outFile = path.join(__dirname, 'symlinks.zip'); await fs.remove(outFile); const outDir = path.join(__dirname, 'symlinks-out'); await fs.remove(outDir); await fs.mkdirp(outDir); await fs.writeFile(outFile, await createZip(files)); await spawnAsync('unzip', [outFile], { cwd: outDir }); const [linkStat, aStat] = await Promise.all([ fs.lstat(path.join(outDir, 'link.txt')), fs.lstat(path.join(outDir, 'a.txt')), ]); assert(linkStat.isSymbolicLink()); assert(aStat.isFile()); }); it('should only match supported node versions', async () => { expect(await getSupportedNodeVersion('10.x', false)).toHaveProperty( 'major', 10 ); expect(await getSupportedNodeVersion('12.x', false)).toHaveProperty( 'major', 12 ); expect(getSupportedNodeVersion('8.11.x', false)).rejects.toThrow(); expect(getSupportedNodeVersion('6.x', false)).rejects.toThrow(); expect(getSupportedNodeVersion('999.x', false)).rejects.toThrow(); expect(getSupportedNodeVersion('foo', false)).rejects.toThrow(); expect(await getSupportedNodeVersion('10.x', true)).toHaveProperty( 'major', 10 ); expect(await getSupportedNodeVersion('12.x', true)).toHaveProperty( 'major', 12 ); expect(getSupportedNodeVersion('8.11.x', true)).rejects.toThrow(); expect(getSupportedNodeVersion('6.x', true)).rejects.toThrow(); expect(getSupportedNodeVersion('999.x', true)).rejects.toThrow(); expect(getSupportedNodeVersion('foo', true)).rejects.toThrow(); }); it('should match all semver ranges', async () => { // See https://docs.npmjs.com/files/package.json#engines expect(await getSupportedNodeVersion('10.0.0')).toHaveProperty('major', 10); expect(await getSupportedNodeVersion('10.x')).toHaveProperty('major', 10); expect(await getSupportedNodeVersion('>=10')).toHaveProperty('major', 12); expect(await getSupportedNodeVersion('>=10.3.0')).toHaveProperty('major', 12); expect(await getSupportedNodeVersion('8.5.0 - 10.5.0')).toHaveProperty( 'major', 10 ); expect(await getSupportedNodeVersion('>=9.5.0 <=10.5.0')).toHaveProperty( 'major', 10 ); expect(await getSupportedNodeVersion('~10.5.0')).toHaveProperty('major', 10); expect(await getSupportedNodeVersion('^10.5.0')).toHaveProperty('major', 10); }); it('should ignore node version in now dev getNodeVersion()', async () => { expect( await getNodeVersion( '/tmp', undefined, { nodeVersion: '1' }, { isDev: true } ) ).toHaveProperty('runtime', 'nodejs'); }); it('should get latest node version', async () => { expect(await getLatestNodeVersion()).toHaveProperty('major', 12); }); it('should throw for discontinued versions', async () => { // Mock a future date so that Node 8 becomes discontinued const realDateNow = Date.now.bind(global.Date); global.Date.now = () => new Date('2020-02-14').getTime(); expect(getSupportedNodeVersion('8.10.x', false)).rejects.toThrow(); expect(getSupportedNodeVersion('8.10.x', true)).rejects.toThrow(); expect(getDiscontinuedNodeVersions().length).toBe(1); expect(getDiscontinuedNodeVersions()[0]).toHaveProperty('range', '8.10.x'); global.Date.now = realDateNow; }); it('should support require by path for legacy builders', () => { const index = require('@vercel/build-utils'); const download2 = require('@vercel/build-utils/fs/download.js'); const getWriteableDirectory2 = require('@vercel/build-utils/fs/get-writable-directory.js'); const glob2 = require('@vercel/build-utils/fs/glob.js'); const rename2 = require('@vercel/build-utils/fs/rename.js'); const { runNpmInstall: runNpmInstall2, } = require('@vercel/build-utils/fs/run-user-scripts.js'); const streamToBuffer2 = require('@vercel/build-utils/fs/stream-to-buffer.js'); const FileBlob2 = require('@vercel/build-utils/file-blob.js'); const FileFsRef2 = require('@vercel/build-utils/file-fs-ref.js'); const FileRef2 = require('@vercel/build-utils/file-ref.js'); const { Lambda: Lambda2 } = require('@vercel/build-utils/lambda.js'); expect(download2).toBe(index.download); expect(getWriteableDirectory2).toBe(index.getWriteableDirectory); expect(glob2).toBe(index.glob); expect(rename2).toBe(index.rename); expect(runNpmInstall2).toBe(index.runNpmInstall); expect(streamToBuffer2).toBe(index.streamToBuffer); expect(FileBlob2).toBe(index.FileBlob); expect(FileFsRef2).toBe(index.FileFsRef); expect(FileRef2).toBe(index.FileRef); expect(Lambda2).toBe(index.Lambda); });