diff --git a/packages/server/__snapshots__/fixture_spec.js b/packages/server/__snapshots__/fixture_spec.ts.js similarity index 100% rename from packages/server/__snapshots__/fixture_spec.js rename to packages/server/__snapshots__/fixture_spec.ts.js diff --git a/packages/server/__snapshots__/terminal_spec.js b/packages/server/__snapshots__/terminal_spec.ts.js similarity index 100% rename from packages/server/__snapshots__/terminal_spec.js rename to packages/server/__snapshots__/terminal_spec.ts.js diff --git a/packages/server/lib/cloud/exception.ts b/packages/server/lib/cloud/exception.ts index 5b4b25bd20c..d146817f711 100644 --- a/packages/server/lib/cloud/exception.ts +++ b/packages/server/lib/cloud/exception.ts @@ -3,7 +3,7 @@ import Bluebird from 'bluebird' import pkg from '@packages/root' import api from './api' import user from './user' -import system from '../util/system' +import * as system from '../util/system' import { stripPath } from './strip_path' const { serializeError } = require('serialize-error') diff --git a/packages/server/lib/controllers/xhrs.ts b/packages/server/lib/controllers/xhrs.ts index d0716a72801..0e609a26f19 100644 --- a/packages/server/lib/controllers/xhrs.ts +++ b/packages/server/lib/controllers/xhrs.ts @@ -1,7 +1,7 @@ import { parseContentType } from '@packages/net-stubbing/lib/server/util' import _ from 'lodash' import Promise from 'bluebird' -import fixture from '../fixture' +import { get as fixtureGet } from '../fixture' const fixturesRe = /^(fx:|fixture:)/ @@ -70,18 +70,19 @@ export = { return respond() }, - _get (resp: string, config: { fixturesFolder: string }): Promise<{ data: any, encoding?: string }> { - const options: { encoding?: string } = {} + _get (resp: string, config: { fixturesFolder: string }): Promise<{ data: any, encoding?: BufferEncoding }> { + const options: { encoding?: BufferEncoding } = {} const file = resp.replace(fixturesRe, '') const [filePath, encoding] = file.split(',') if (encoding) { - options.encoding = encoding + options.encoding = encoding as BufferEncoding } - return fixture.get(config.fixturesFolder, filePath, options) + // @ts-expect-error - bluebird to promise type mismatch + return fixtureGet(config.fixturesFolder, filePath, options) .then((bytes: any) => { return { data: bytes, diff --git a/packages/server/lib/files.js b/packages/server/lib/files.js deleted file mode 100644 index ea497c1c400..00000000000 --- a/packages/server/lib/files.js +++ /dev/null @@ -1,64 +0,0 @@ -const Bluebird = require('bluebird') -const path = require('path') -const { fs } = require('./util/fs') - -module.exports = { - readFile (projectRoot, options = {}) { - const filePath = path.resolve(projectRoot, options.file) - const readFn = (path.extname(filePath) === '.json' && options.encoding !== null) ? fs.readJsonAsync : fs.readFileAsync - - // https://github.com/cypress-io/cypress/issues/1558 - // If no encoding is specified, then Cypress has historically defaulted - // to `utf8`, because of it's focus on text files. This is in contrast to - // NodeJs, which defaults to binary. We allow users to pass in `null` - // to restore the default node behavior. - return readFn(filePath, options.encoding === undefined ? 'utf8' : options.encoding) - .then((contents) => { - return { - contents, - filePath, - } - }) - .catch((err) => { - err.originalFilePath = options.file - err.filePath = filePath - throw err - }) - }, - - readFiles (projectRoot, options = {}) { - return Bluebird.map(options.files, (file) => { - return this.readFile(projectRoot, { - file: file.path, - encoding: file.encoding, - }) - .then(({ contents, filePath }) => { - return { - ...file, - filePath, - contents, - } - }) - }) - }, - - writeFile (projectRoot, options = {}) { - const filePath = path.resolve(projectRoot, options.fileName) - const writeOptions = { - encoding: options.encoding === undefined ? 'utf8' : options.encoding, - flag: options.flag || 'w', - } - - return fs.outputFile(filePath, options.contents, writeOptions) - .then(() => { - return { - contents: options.contents, - filePath, - } - }) - .catch((err) => { - err.filePath = filePath - throw err - }) - }, -} diff --git a/packages/server/lib/files.ts b/packages/server/lib/files.ts new file mode 100644 index 00000000000..4af8e22712c --- /dev/null +++ b/packages/server/lib/files.ts @@ -0,0 +1,69 @@ +import path from 'path' +import { fs } from './util/fs' + +export async function readFile (projectRoot: string, options: { file: string, encoding?: BufferEncoding } = { file: '', encoding: 'utf8' }) { + const filePath = path.resolve(projectRoot, options.file) + + // https://github.com/cypress-io/cypress/issues/1558 + // If no encoding is specified, then Cypress has historically defaulted + // to `utf8`, because of it's focus on text files. This is in contrast to + // NodeJs, which defaults to binary. We allow users to pass in `null` + // to restore the default node behavior. + try { + let contents + + if (path.extname(filePath) === '.json' && options.encoding !== null) { + contents = await fs.readJsonAsync(filePath, options.encoding === undefined ? 'utf8' : options.encoding) + } else { + contents = await fs.readFileAsync(filePath, { + encoding: options.encoding === undefined ? 'utf8' : options.encoding, + }) + } + + return { + contents, + filePath, + } + } catch (err) { + err.originalFilePath = options.file + err.filePath = filePath + throw err + } +} + +export async function readFiles (projectRoot: string, options: { files: { path: string, encoding?: BufferEncoding }[] } = { files: [] }) { + const files = await Promise.all(options.files.map(async (file) => { + const { contents, filePath } = await readFile(projectRoot, { + file: file.path, + encoding: file.encoding, + }) + + return { + ...file, + filePath, + contents, + } + })) + + return files +} + +export async function writeFile (projectRoot: string, options: { fileName: string, contents: string, encoding?: BufferEncoding, flag?: string } = { fileName: '', contents: '', encoding: 'utf8', flag: 'w' }) { + const filePath = path.resolve(projectRoot, options.fileName) + const writeOptions = { + encoding: options.encoding === undefined ? 'utf8' : options.encoding, + flag: options.flag || 'w', + } + + try { + await fs.outputFile(filePath, options.contents, writeOptions) + + return { + contents: options.contents, + filePath, + } + } catch (err) { + err.filePath = filePath + throw err + } +} diff --git a/packages/server/lib/fixture.js b/packages/server/lib/fixture.js deleted file mode 100644 index c716eedaff0..00000000000 --- a/packages/server/lib/fixture.js +++ /dev/null @@ -1,212 +0,0 @@ -const path = require('path') -const check = require('syntax-error') -const debug = require('debug')('cypress:server:fixture') -const coffee = require('coffeescript') -const Promise = require('bluebird') -const jsonParseBetterErrors = require('json-parse-even-better-errors') -const stripAnsi = require('strip-ansi') - -const errors = require('./errors') -const { fs } = require('./util/fs') -const glob = require('./util/glob') - -const extensions = [ - '.json', - '.js', - '.coffee', - '.html', - '.txt', - '.csv', - '.png', - '.jpg', - '.jpeg', - '.gif', - '.tif', - '.tiff', - '.zip', -] - -const queue = {} - -const friendlyJsonParse = function (s) { - jsonParseBetterErrors(s) // should throw an error with better formatting - - return JSON.parse(s) // actually parses correctly all the edge cases -} - -module.exports = { - get (fixturesFolder, filePath, options = {}) { - const p = path.join(fixturesFolder, filePath) - const fixture = path.basename(p) - - // if the file exists, go ahead and parse it - // otherwise, glob for potential extensions - return this.fileExists(p) - .then(function () { - debug('fixture exact name exists', p) - - return this.parseFile(p, fixture, options) - }).catch(function (e) { - if (e.code !== 'ENOENT') { - throw e - } - - const pattern = `${p}{${extensions.join(',')}}` - - return glob(pattern, { - nosort: true, - nodir: true, - }) - .bind(this) - .then(function (matches) { - if (matches.length === 0) { - const relativePath = path.relative('.', p) - - // TODO: there's no reason this error should be in - // the @packages/error list, it should be written in - // the driver since this error can only occur within - // driver commands and not outside of the test runner - const err = errors.get('FIXTURE_NOT_FOUND', relativePath, extensions) - - err.message = stripAnsi(err.message) - throw err - } - - debug('fixture matches found, using the first', matches) - - const ext = path.extname(matches[0]) - - return this.parseFile(p + ext, fixture, options) - }) - }) - }, - - fileExists (p) { - return fs.statAsync(p).bind(this) - .then((stat) => { - // check for files, not directories - // https://github.com/cypress-io/cypress/issues/3739 - if (stat.isDirectory()) { - const err = new Error() - - err.code = 'ENOENT' - throw err - } - }) - }, - - parseFile (p, fixture, options) { - if (queue[p]) { - return Promise.delay(1).then(() => { - return this.parseFile(p, fixture, options) - }) - } - - queue[p] = true - - const cleanup = () => { - return delete queue[p] - } - - return this.fileExists(p) - .then(function () { - const ext = path.extname(p) - - return this.parseFileByExtension(p, fixture, ext, options) - }).then((ret) => { - cleanup() - - return ret - }).catch((err) => { - cleanup() - - throw err - }) - }, - - parseFileByExtension (p, fixture, ext, options = {}) { - // If an encoding is specified, return the raw file content instead of - // parsing. - if (typeof options.encoding !== 'undefined') { - return this.parse(p, fixture, options.encoding) - } - - switch (ext) { - case '.json': return this.parseJson(p, fixture) - case '.js': return this.parseJs(p, fixture) - case '.coffee': return this.parseCoffee(p, fixture) - case '.html': return this.parseHtml(p, fixture) - case '.png': case '.jpg': case '.jpeg': case '.gif': case '.tif': case '.tiff': case '.zip': - return this.parse(p, fixture, options.encoding) - default: - return this.parse(p, fixture, options.encoding || 'utf8') - } - }, - - parseJson (p, fixture) { - return fs.readFileAsync(p, 'utf8') - .bind(this) - .then(friendlyJsonParse) - .catch((err) => { - throw new Error(`'${fixture}' is not valid JSON.\n${err.message}`) - }) - }, - - parseJs (p, fixture) { - return fs.readFileAsync(p, 'utf8') - .bind(this) - .then((str) => { - let obj - - try { - obj = eval(`(${str})`) - } catch (e) { - const err = check(str, fixture) - - if (err) { - throw err - } - - throw e - } - - return obj - }).catch((err) => { - throw new Error(`'${fixture}' is not a valid JavaScript object.\n${err.toString()}`) - }) - }, - - parseCoffee (p, fixture) { - const dc = process.env.NODE_DISABLE_COLORS - - process.env.NODE_DISABLE_COLORS = '0' - - return fs.readFileAsync(p, 'utf8') - .bind(this) - .then((str) => { - str = coffee.compile(str, { bare: true }) - - return eval(str) - }).catch((err) => { - throw new Error(`'${fixture} is not a valid CoffeeScript object.\n${err.toString()}`) - }).finally(() => { - return process.env.NODE_DISABLE_COLORS = dc - }) - }, - - parseHtml (p, fixture) { - return fs.readFileAsync(p, 'utf8') - .bind(this) - .catch((err) => { - throw new Error(`Unable to parse '${fixture}'.\n${err.toString()}`) - }) - }, - - parse (p, fixture, encoding) { - return fs.readFileAsync(p, encoding) - .bind(this) - .catch((err) => { - throw new Error(`Unable to parse '${fixture}'.\n${err.toString()}`) - }) - }, -} diff --git a/packages/server/lib/fixture.ts b/packages/server/lib/fixture.ts new file mode 100644 index 00000000000..f2ea1d85932 --- /dev/null +++ b/packages/server/lib/fixture.ts @@ -0,0 +1,216 @@ +import path from 'path' +import check from 'syntax-error' +import debugModule from 'debug' +import coffee from 'coffeescript' +import Bluebird from 'bluebird' +import jsonParseBetterErrors from 'json-parse-even-better-errors' +import stripAnsi from 'strip-ansi' +import * as errors from './errors' +import { fs } from './util/fs' +import glob from './util/glob' +import type { ObjectEncodingOptions } from 'fs-extra' + +const debug = debugModule('cypress:server:fixture') + +const extensions = [ + '.json', + '.js', + '.coffee', + '.html', + '.txt', + '.csv', + '.png', + '.jpg', + '.jpeg', + '.gif', + '.tif', + '.tiff', + '.zip', +] + +const queue = {} + +const friendlyJsonParse = function (s) { + jsonParseBetterErrors(s) // should throw an error with better formatting + + return JSON.parse(s) // actually parses correctly all the edge cases +} + +export async function get (fixturesFolder: string, filePath: string, options: { encoding?: (ObjectEncodingOptions & { flag?: string | undefined }) | BufferEncoding | null | undefined } = {}) { + const p = path.join(fixturesFolder, filePath) + const fixture = path.basename(p) + + // if the file exists, go ahead and parse it + // otherwise, glob for potential extensions + + try { + await fileExists(p) + debug('fixture exact name exists', p) + + return parseFile(p, fixture, options) + } catch (e) { + if (e.code !== 'ENOENT') { + throw e + } + + const pattern = `${p}{${extensions.join(',')}}` + + // @ts-ignore as v8-snapshot package is typechecking this incorrectly + const matches = await glob(pattern, { + nosort: true, + nodir: true, + }) + + if (matches.length === 0) { + const relativePath = path.relative('.', p) + + // TODO: there's no reason this error should be in + // the @packages/error list, it should be written in + // the driver since this error can only occur within + // driver commands and not outside of the test runner + const err = errors.get('FIXTURE_NOT_FOUND', relativePath, extensions) + + err.message = stripAnsi(err.message) + throw err + } + + debug('fixture matches found, using the first', matches) + + const ext = path.extname(matches[0]) + + return parseFile(p + ext, fixture, options) + } +} + +export async function fileExists (p: string) { + const stat = await fs.statAsync(p) + + // check for files, not directories + // https://github.com/cypress-io/cypress/issues/3739 + if (stat?.isDirectory()) { + const err = new Error() + + // @ts-expect-error - code isn't typed on Error + err.code = 'ENOENT' + throw err + } +} + +export async function parseFile (p: string, fixture: string, options: { encoding?: (ObjectEncodingOptions & { flag?: string | undefined }) | BufferEncoding | null } = {}) { + if (queue[p]) { + await Bluebird.delay(1) + + return parseFile(p, fixture, options) + } + + queue[p] = true + + const cleanup = () => { + return delete queue[p] + } + + try { + await fileExists(p) + const ext = path.extname(p) + + const ret = await parseFileByExtension(p, fixture, ext, options) + + cleanup() + + return ret + } catch (err) { + cleanup() + throw err + } +} + +export async function parseFileByExtension (p: string, fixture: string, ext: string, options: { encoding?: (ObjectEncodingOptions & { flag?: string | undefined }) | BufferEncoding | null } = {}) { + // If an encoding is specified, return the raw file content instead of + // parsing. + if (typeof options.encoding !== 'undefined') { + return parse(p, fixture, options.encoding) + } + + switch (ext) { + case '.json': return parseJson(p, fixture) + case '.js': return parseJs(p, fixture) + case '.coffee': return parseCoffee(p, fixture) + case '.html': return parseHtml(p, fixture) + case '.png': case '.jpg': case '.jpeg': case '.gif': case '.tif': case '.tiff': case '.zip': + return parse(p, fixture, options.encoding) + default: + return parse(p, fixture, options.encoding || 'utf8') + } +} + +export async function parseJson (p: string, fixture: string) { + try { + const content = await fs.readFileAsync(p, 'utf8') + + return friendlyJsonParse(content) + } catch (err) { + throw new Error(`'${fixture}' is not valid JSON.\n${err.message}`) + } +} + +export async function parseJs (p: string, fixture: string) { + try { + const str = await fs.readFileAsync(p, 'utf8') + + let obj + + try { + obj = eval(`(${str})`) + } catch (e) { + const err = check(str, fixture) + + if (err) { + throw err + } + + throw e + } + + return obj + } catch (err) { + throw new Error(`'${fixture}' is not a valid JavaScript object.\n${err.toString()}`) + } +} + +export async function parseCoffee (p: string, fixture: string) { + const dc = process.env.NODE_DISABLE_COLORS + + process.env.NODE_DISABLE_COLORS = '0' + + try { + const content = await fs.readFileAsync(p, 'utf8') + + const str = coffee.compile(content, { bare: true }) + + return eval(str as string) + } catch (err) { + throw new Error(`'${fixture} is not a valid CoffeeScript object.\n${err.toString()}`) + } finally { + process.env.NODE_DISABLE_COLORS = dc + } +} + +export async function parseHtml (p: string, fixture: string) { + try { + const content = await fs.readFileAsync(p, 'utf8') + + return content + } catch (err) { + throw new Error(`Unable to parse '${fixture}'.\n${err.toString()}`) + } +} + +export async function parse (p: string, fixture: string, encoding: (ObjectEncodingOptions & { flag?: string | undefined }) | BufferEncoding | null | undefined) { + try { + const content = await fs.readFileAsync(p, encoding) + + return content + } catch (err) { + throw new Error(`Unable to parse '${fixture}'.\n${err.toString()}`) + } +} diff --git a/packages/server/lib/log.js b/packages/server/lib/log.js deleted file mode 100644 index 61425870d49..00000000000 --- a/packages/server/lib/log.js +++ /dev/null @@ -1,13 +0,0 @@ -// lightweight logging for Node -// only shows log messages if running with -// DEBUG=cypress:start ... -// or -// DEBUG=cypress:* ... -// use -// log = require('./log') -// log('working in %s', process.cwd()) -// If you need a logger that might be very specific -// you can construct it yourself, just make sure -// to prefix label with "cypress:server:", for example -// log = require('debug')('cypress:server:bundle') -module.exports = require('debug')('cypress:server') diff --git a/packages/server/lib/modes/run.ts b/packages/server/lib/modes/run.ts index 1ade2e04efb..d418e028858 100644 --- a/packages/server/lib/modes/run.ts +++ b/packages/server/lib/modes/run.ts @@ -18,7 +18,7 @@ import runEvents from '../plugins/run_events' import * as env from '../util/env' import trash from '../util/trash' import { id as randomId } from '../util/random' -import system from '../util/system' +import * as system from '../util/system' import chromePolicyCheck from '../util/chrome_policy_check' import type { SpecWithRelativeRoot, SpecFile, TestingType, OpenProjectLaunchOpts, FoundBrowser, BrowserVideoController, VideoRecording, ProcessOptions, ProtocolManagerShape, AutomationCommands } from '@packages/types' import type { Cfg, ProjectBase } from '../project-base' @@ -1131,6 +1131,7 @@ async function ready (options: ReadyOptions) { socketId, parallel, onError, + // @ts-expect-error - browser is not typed correctly browser, project, runUrl, diff --git a/packages/server/lib/privileged-commands/privileged-commands-manager.ts b/packages/server/lib/privileged-commands/privileged-commands-manager.ts index f6cb9c6b479..464e3db7b18 100644 --- a/packages/server/lib/privileged-commands/privileged-commands-manager.ts +++ b/packages/server/lib/privileged-commands/privileged-commands-manager.ts @@ -4,7 +4,7 @@ import path from 'path' import { v4 as uuidv4 } from 'uuid' import * as exec from '../exec' -import files from '../files' +import * as files from '../files' import { fs } from '../util/fs' import task from '../task' diff --git a/packages/server/lib/project-base.ts b/packages/server/lib/project-base.ts index eff2a8bb0e6..f7d64b2905b 100644 --- a/packages/server/lib/project-base.ts +++ b/packages/server/lib/project-base.ts @@ -15,7 +15,7 @@ import * as savedState from './saved_state' import { SocketCt } from './socket-ct' import { SocketE2E } from './socket-e2e' import { ensureProp } from './util/class-helpers' -import system from './util/system' +import * as system from './util/system' import type { BannersState, FoundBrowser, diff --git a/packages/server/lib/server-base.ts b/packages/server/lib/server-base.ts index 6879b451a03..2e11b6218d0 100644 --- a/packages/server/lib/server-base.ts +++ b/packages/server/lib/server-base.ts @@ -37,7 +37,7 @@ import { resourceTypeAndCredentialManager, ResourceTypeAndCredentialManager } fr import * as fileServer from './file_server' import appData from './util/app_data' import { graphqlWS } from '@packages/data-context/graphql/makeGraphQLServer' -import statusCode from './util/status_code' +import * as statusCode from './util/status_code' import headersUtil from './util/headers' import stream from 'stream' import isHtml from 'is-html' diff --git a/packages/server/lib/socket-base.ts b/packages/server/lib/socket-base.ts index 31f4bc5d80e..5dc20eddfb2 100644 --- a/packages/server/lib/socket-base.ts +++ b/packages/server/lib/socket-base.ts @@ -9,7 +9,7 @@ import * as socketIo from '@packages/socket' import { CDPSocketServer } from '@packages/socket' import * as errors from './errors' -import fixture from './fixture' +import { get as fixtureGet } from './fixture' import { ensureProp } from './util/class-helpers' import { getUserEditor, setUserEditor } from './util/editors' import { openFile, OpenFileDetails } from './util/file-opener' @@ -202,7 +202,7 @@ export class SocketBase { return automation.request(message, data, onAutomationClientRequestCallback) } - const getFixture = (path, opts) => fixture.get(config.fixturesFolder, path, opts) + const getFixture = (path, opts) => fixtureGet(config.fixturesFolder, path, opts) this.getIos().forEach((io) => { io?.on('connection', (socket: Socket & { inReporterRoom?: boolean, inRunnerRoom?: boolean }) => { diff --git a/packages/server/lib/util/file.ts b/packages/server/lib/util/file.ts index d646f131672..cc72e6795d9 100644 --- a/packages/server/lib/util/file.ts +++ b/packages/server/lib/util/file.ts @@ -159,7 +159,6 @@ export class File { .then(() => { debugVerbose('read %s', this.path) - // @ts-expect-error return fs.readJsonAsync(this.path, 'utf8') }) .catch((err) => { diff --git a/packages/server/lib/util/fs.ts b/packages/server/lib/util/fs.ts index 89a3f708934..23952e672ee 100644 --- a/packages/server/lib/util/fs.ts +++ b/packages/server/lib/util/fs.ts @@ -25,6 +25,7 @@ interface PromisifiedFsExtra { writeFileAsync: Promisified pathExistsAsync: Promisified outputFileAsync: Promisified + readJsonAsync: Promisified } interface Clip { diff --git a/packages/server/lib/util/print-run.ts b/packages/server/lib/util/print-run.ts index 9a2822600a9..5d387c2fd1d 100644 --- a/packages/server/lib/util/print-run.ts +++ b/packages/server/lib/util/print-run.ts @@ -9,13 +9,13 @@ import humanTime from './human_time' import duration from './duration' import newlines from './newlines' import * as env from './env' -import terminal from './terminal' +import * as terminal from './terminal' import { getIsCi } from './ci_provider' import * as experiments from '../experiments' import type { SpecFile, ProtocolError } from '@packages/types' import type { Cfg } from '../project-base' import type { Browser } from '../browsers/types' -import type { Table } from 'cli-table3' +import type { HorizontalAlignment, Table } from 'cli-table3' import type { CypressRunResult } from '../modes/results' import type { IArtifact, ArtifactUploadResult } from '../cloud/artifacts/artifact' @@ -314,7 +314,7 @@ export function renderSummaryTable (runUrl: string | undefined, results: Cypress }) if (runs && runs.length) { - const colAligns = ['left', 'left', 'right', 'right', 'right', 'right', 'right', 'right'] + const colAligns: HorizontalAlignment[] = ['left', 'left', 'right', 'right', 'right', 'right', 'right', 'right'] const colWidths = [3, 41, 11, 9, 9, 9, 9, 9] const table1 = terminal.table({ diff --git a/packages/server/lib/util/resolve.js b/packages/server/lib/util/resolve.js deleted file mode 100644 index fc17c243961..00000000000 --- a/packages/server/lib/util/resolve.js +++ /dev/null @@ -1,29 +0,0 @@ -const debug = require('debug')('cypress:server:plugins') - -module.exports = { - /** - * Resolves the path to 'typescript' module. - * - * @param {projectRoot} path to the project root - * @returns {string|null} path if typescript exists, otherwise null - */ - typescript: (projectRoot) => { - if (process.env['CYPRESS_INTERNAL_NO_TYPESCRIPT'] === '1' || !projectRoot) { - return null - } - - try { - debug('resolving typescript with projectRoot %o', projectRoot) - - const resolved = require.resolve('typescript', { paths: [projectRoot] }) - - debug('resolved typescript %s', resolved) - - return resolved - } catch (e) { - debug('could not resolve typescript, error: %s', e.message) - - return null - } - }, -} diff --git a/packages/server/lib/util/resolve.ts b/packages/server/lib/util/resolve.ts new file mode 100644 index 00000000000..23b0d031124 --- /dev/null +++ b/packages/server/lib/util/resolve.ts @@ -0,0 +1,28 @@ +import debugModule from 'debug' +const debug = debugModule('cypress:server:plugins') + +/** + * Resolves the path to 'typescript' module. + * + * @param {projectRoot} path to the project root + * @returns {string|null} path if typescript exists, otherwise null + */ +export const typescript = (projectRoot) => { + if (process.env['CYPRESS_INTERNAL_NO_TYPESCRIPT'] === '1' || !projectRoot) { + return null + } + + try { + debug('resolving typescript with projectRoot %o', projectRoot) + + const resolved = require.resolve('typescript', { paths: [projectRoot] }) + + debug('resolved typescript %s', resolved) + + return resolved + } catch (e) { + debug('could not resolve typescript, error: %s', e.message) + + return null + } +} diff --git a/packages/server/lib/util/status_code.js b/packages/server/lib/util/status_code.js deleted file mode 100644 index e141141bfcc..00000000000 --- a/packages/server/lib/util/status_code.js +++ /dev/null @@ -1,12 +0,0 @@ -const http = require('http') -const isOkStatusCodeRe = /^[2|3]\d+$/ - -module.exports = { - isOk (code) { - return code && isOkStatusCodeRe.test(code) - }, - - getText (code) { - return http.STATUS_CODES[code] || 'Unknown Status Code' - }, -} diff --git a/packages/server/lib/util/status_code.ts b/packages/server/lib/util/status_code.ts new file mode 100644 index 00000000000..17bf00ebbc0 --- /dev/null +++ b/packages/server/lib/util/status_code.ts @@ -0,0 +1,11 @@ +import http from 'http' + +const isOkStatusCodeRe = /^[2|3]\d+$/ + +export const isOk = (code: number | string): boolean => { + return !!code && isOkStatusCodeRe.test(code as string) +} + +export const getText = (code: number | string): string => { + return http.STATUS_CODES[code] || 'Unknown Status Code' +} diff --git a/packages/server/lib/util/system.js b/packages/server/lib/util/system.js deleted file mode 100644 index 19bcb7da6b6..00000000000 --- a/packages/server/lib/util/system.js +++ /dev/null @@ -1,35 +0,0 @@ -const os = require('os') -const Promise = require('bluebird') -const si = require('systeminformation') - -const getOsVersion = () => { - return Promise.try(() => { - return si.osInfo() - .then((osInfo) => { - if (osInfo.distro && osInfo.release) { - return `${osInfo.distro} - ${osInfo.release}` - } - - return os.release() - }).catch(() => { - return os.release() - }) - }) -} - -module.exports = { - info () { - return getOsVersion() - .then((osVersion) => { - return { - osName: os.platform(), - osVersion, - osCpus: os.cpus(), - osMemory: { - free: os.freemem(), - total: os.totalmem(), - }, - } - }) - }, -} diff --git a/packages/server/lib/util/system.ts b/packages/server/lib/util/system.ts new file mode 100644 index 00000000000..88f7349f161 --- /dev/null +++ b/packages/server/lib/util/system.ts @@ -0,0 +1,30 @@ +import os from 'os' +import si from 'systeminformation' + +const getOsVersion = async () => { + try { + const osInfo = await si.osInfo() + + if (osInfo.distro && osInfo.release) { + return `${osInfo.distro} - ${osInfo.release}` + } + + return os.release() + } catch (error) { + return os.release() + } +} + +export const info = async () => { + const osVersion = await getOsVersion() + + return { + osName: os.platform(), + osVersion, + osCpus: os.cpus(), + osMemory: { + free: os.freemem(), + total: os.totalmem(), + }, + } +} diff --git a/packages/server/lib/util/terminal.js b/packages/server/lib/util/terminal.ts similarity index 81% rename from packages/server/lib/util/terminal.js rename to packages/server/lib/util/terminal.ts index 626d6a16c0a..5717b55b732 100644 --- a/packages/server/lib/util/terminal.js +++ b/packages/server/lib/util/terminal.ts @@ -1,17 +1,18 @@ -const _ = require('lodash') -const chalk = require('chalk') -const Table = require('cli-table3') -const utils = require('cli-table3/src/utils') -const widestLine = require('widest-line') -const terminalSize = require('./terminal-size') +import _ from 'lodash' +import chalk from 'chalk' +import Table from 'cli-table3' +import utils from 'cli-table3/src/utils' +import widestLine from 'widest-line' +import { get as getTerminalSize } from './terminal-size' +import type { HorizontalAlignment } from 'cli-table3' const MAXIMUM_SIZE = 100 const EXPECTED_SUM = 100 -const getMaximumColumns = () => { +export const getMaximumColumns = () => { // get the maximum amount of columns // that can fit in the terminal - return Math.min(MAXIMUM_SIZE, terminalSize.get().columns) + return Math.min(MAXIMUM_SIZE, getTerminalSize().columns) } const getBordersLength = (left, right) => { @@ -23,9 +24,9 @@ const getBordersLength = (left, right) => { .value() } -const renderTables = (...tables) => { +export const renderTables = (...tables) => { return _ - .chain([]) + .chain([]) .concat(tables) .invokeMap('toString') .join('\n') @@ -130,7 +131,7 @@ const wrapBordersInGray = (chars) => { }) } -const table = (options = {}) => { +export const table = (options: { type: string, colWidths?: number[], colAligns?: HorizontalAlignment[], head?: string[], chars?: Record, style?: { [key: string]: any } }) => { const { type } = options const defaults = utils.mergeOptions({}) @@ -161,7 +162,7 @@ const table = (options = {}) => { if (bordersLength > 0) { // redistribute the columns to account for borders on each side... // and subtract borders size from the largest width cell - const largestCellWidth = _.max(colWidths) + const largestCellWidth = _.max(colWidths) ?? 0 const index = _.indexOf(colWidths, largestCellWidth) @@ -177,7 +178,7 @@ const table = (options = {}) => { return new Table(options) } -const header = (message, options = {}) => { +export const header = (message: string, options: { color?: string[] | null } = {}) => { _.defaults(options, { color: null, }) @@ -185,7 +186,8 @@ const header = (message, options = {}) => { message = ` (${chalk.underline.bold(message)})` if (options.color) { - const colors = [].concat(options.color) + // @ts-expect-error type is cast incorrectly to never + const colors = [].concat(options.color) message = _.reduce(colors, (memo, color) => { return chalk[color](memo) @@ -195,21 +197,9 @@ const header = (message, options = {}) => { console.log(message) // eslint-disable-line no-console } -const divider = (symbol, color = 'gray') => { +export const divider = (symbol, color = 'gray') => { const cols = getMaximumColumns() const str = symbol.repeat(cols) console.log(chalk[color](str)) // eslint-disable-line no-console } - -module.exports = { - table, - - header, - - divider, - - renderTables, - - getMaximumColumns, -} diff --git a/packages/server/lib/util/tty.js b/packages/server/lib/util/tty.ts similarity index 82% rename from packages/server/lib/util/tty.js rename to packages/server/lib/util/tty.ts index 0619e7944a2..5cd6f76d4b6 100644 --- a/packages/server/lib/util/tty.js +++ b/packages/server/lib/util/tty.ts @@ -1,10 +1,10 @@ -const tty = require('tty') -const terminalSize = require('./terminal-size') +import tty from 'tty' +import { get as getTerminalSize } from './terminal-size' // polyfills node's getWindowSize // by returning an array of columns/rows -function getWindowSize () { - const { columns, rows } = terminalSize.get() +export function getWindowSize () { + const { columns, rows } = getTerminalSize() return [columns, rows] } @@ -17,7 +17,7 @@ function patchStream (patched, name) { patched[stream.fd] = true } -const override = () => { +export function override () { const isatty = tty.isatty const patched = { @@ -54,9 +54,3 @@ const override = () => { return } - -module.exports = { - override, - - getWindowSize, -} diff --git a/packages/server/start-cypress.js b/packages/server/start-cypress.js index df0ee1d27d5..df5546396f0 100644 --- a/packages/server/start-cypress.js +++ b/packages/server/start-cypress.js @@ -2,6 +2,7 @@ const electronApp = require('./lib/util/electron-app') const { telemetry, OTLPTraceExporterCloud } = require('@packages/telemetry') const { apiRoutes } = require('./lib/cloud/routes') const encryption = require('./lib/cloud/encryption') +const { override: overrideTty } = require('./lib/util/tty') const { calculateCypressInternalEnv, configureLongStackTraces } = require('./lib/environment') @@ -64,7 +65,7 @@ const fs = require('fs') patchFs(fs) // override tty if we're being forced to -require('./lib/util/tty').override() +overrideTty() if (process.env.CY_NET_PROFILE && isRunningElectron) { const netProfiler = require('./lib/util/net_profiler')() diff --git a/packages/server/test/unit/cloud/exceptions_spec.js b/packages/server/test/unit/cloud/exceptions_spec.js index f73cdeac7f4..6a29cd8e402 100644 --- a/packages/server/test/unit/cloud/exceptions_spec.js +++ b/packages/server/test/unit/cloud/exceptions_spec.js @@ -1,5 +1,3 @@ -require('../../spec_helper') - delete global.fs const api = require('../../../lib/cloud/api').default diff --git a/packages/server/test/unit/files_spec.js b/packages/server/test/unit/files_spec.js deleted file mode 100644 index 1e37bab7c3c..00000000000 --- a/packages/server/test/unit/files_spec.js +++ /dev/null @@ -1,133 +0,0 @@ -require('../spec_helper') - -const files = require('../../lib/files') -const FixturesHelper = require('@tooling/system-tests') - -let ctx - -describe('lib/files', () => { - before(async function () { - const { setCtx, makeDataContext, clearCtx } = require('../../lib/makeDataContext') - - // Clear and set up DataContext - await clearCtx() - setCtx(makeDataContext({})) - ctx = require('../../lib/makeDataContext').getCtx() - - FixturesHelper.scaffold() - this.todosPath = FixturesHelper.projectPath('todos') - - await ctx.actions.project.setCurrentProjectAndTestingTypeForTestSetup(this.todosPath) - - const cfg = await ctx.lifecycleManager.getFullInitialConfig() - - this.config = cfg - this.projectRoot = cfg.projectRoot - - await ctx.actions.project.setCurrentProjectAndTestingTypeForTestSetup(this.projectRoot) - }) - - after(() => { - return FixturesHelper.remove() - }) - - context('#readFile', () => { - it('returns contents and full file path', function () { - return files.readFile(this.projectRoot, { file: 'tests/_fixtures/message.txt' }).then(({ contents, filePath }) => { - expect(contents).to.eq('foobarbaz') - - expect(filePath).to.include('/cy-projects/todos/tests/_fixtures/message.txt') - }) - }) - - it('returns uses utf8 by default', function () { - return files.readFile(this.projectRoot, { file: 'tests/_fixtures/ascii.foo' }).then(({ contents }) => { - expect(contents).to.eq('\n') - }) - }) - - it('uses encoding specified in options', function () { - return files.readFile(this.projectRoot, { file: 'tests/_fixtures/ascii.foo', encoding: 'ascii' }).then(({ contents }) => { - expect(contents).to.eq('o#?\n') - }) - }) - - // https://github.com/cypress-io/cypress/issues/1558 - it('explicit null encoding is sent to driver as a Buffer', function () { - return files.readFile(this.projectRoot, { file: 'tests/_fixtures/ascii.foo', encoding: null }).then(({ contents }) => { - expect(contents).to.eql(Buffer.from('\n')) - }) - }) - - it('parses json to valid JS object', function () { - return files.readFile(this.projectRoot, { file: 'tests/_fixtures/users.json' }).then(({ contents }) => { - expect(contents).to.eql([ - { - id: 1, - name: 'brian', - }, { - id: 2, - name: 'jennifer', - }, - ]) - }) - }) - }) - - context('#writeFile', () => { - it('writes the file\'s contents and returns contents and full file path', function () { - return files.writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'foo' }).then(() => { - return files.readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents, filePath }) => { - expect(contents).to.equal('foo') - - expect(filePath).to.include('/cy-projects/todos/.projects/write_file.txt') - }) - }) - }) - - it('uses encoding specified in options', function () { - return files.writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: '', encoding: 'ascii' }).then(() => { - return files.readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { - expect(contents).to.equal('�') - }) - }) - }) - - // https://github.com/cypress-io/cypress/issues/1558 - it('explicit null encoding is written exactly as received', function () { - return files.writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: Buffer.from(''), encoding: null }).then(() => { - return files.readFile(this.projectRoot, { file: '.projects/write_file.txt', encoding: null }).then(({ contents }) => { - expect(contents).to.eql(Buffer.from('')) - }) - }) - }) - - it('overwrites existing file by default', function () { - return files.writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'foo' }).then(() => { - return files.readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { - expect(contents).to.equal('foo') - - return files.writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'bar' }).then(() => { - return files.readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { - expect(contents).to.equal('bar') - }) - }) - }) - }) - }) - - it('appends content to file when specified', function () { - return files.writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'foo' }).then(() => { - return files.readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { - expect(contents).to.equal('foo') - - return files.writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'bar', flag: 'a+' }).then(() => { - return files.readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { - expect(contents).to.equal('foobar') - }) - }) - }) - }) - }) - }) -}) diff --git a/packages/server/test/unit/files_spec.ts b/packages/server/test/unit/files_spec.ts new file mode 100644 index 00000000000..fc2c42c33c2 --- /dev/null +++ b/packages/server/test/unit/files_spec.ts @@ -0,0 +1,144 @@ +import { readFile, writeFile } from '../../lib/files' +import FixturesHelper from '@tooling/system-tests' +import { setCtx, makeDataContext, clearCtx } from '../../lib/makeDataContext' +import { getCtx } from '@packages/data-context' +let ctx + +describe('lib/files', () => { + before(async function () { + // Clear and set up DataContext + await clearCtx() + // @ts-expect-error + setCtx(makeDataContext({})) + ctx = getCtx() + + // needed to run these tests locally + // sinon.stub(ctx.browser, 'machineBrowsers').resolves([ + // { + // channel: 'stable', + // displayName: 'Electron', + // family: 'chromium', + // majorVersion: '123', + // name: 'electron', + // path: 'path-to-browser-one', + // version: '123.45.67', + // }, + // ]) + + FixturesHelper.scaffold() + this.todosPath = FixturesHelper.projectPath('todos') + + await ctx.actions.project.setCurrentProjectAndTestingTypeForTestSetup(this.todosPath) + + const cfg = await ctx.lifecycleManager.getFullInitialConfig() + + this.config = cfg + this.projectRoot = cfg.projectRoot + + await ctx.actions.project.setCurrentProjectAndTestingTypeForTestSetup(this.projectRoot) + }) + + after(() => { + return FixturesHelper.remove() + }) + + context('#readFile', () => { + it('returns contents and full file path', function () { + return readFile(this.projectRoot, { file: 'tests/_fixtures/message.txt' }).then(({ contents, filePath }) => { + expect(contents).to.eq('foobarbaz') + + expect(filePath).to.include('/cy-projects/todos/tests/_fixtures/message.txt') + }) + }) + + it('returns uses utf8 by default', function () { + return readFile(this.projectRoot, { file: 'tests/_fixtures/ascii.foo' }).then(({ contents }) => { + expect(contents).to.eq('\n') + }) + }) + + it('uses encoding specified in options', function () { + return readFile(this.projectRoot, { file: 'tests/_fixtures/ascii.foo', encoding: 'ascii' }).then(({ contents }) => { + expect(contents).to.eq('o#?\n') + }) + }) + + // https://github.com/cypress-io/cypress/issues/1558 + it('explicit null encoding is sent to driver as a Buffer', function () { + return readFile(this.projectRoot, { file: 'tests/_fixtures/ascii.foo', encoding: null }).then(({ contents }) => { + expect(contents).to.eql(Buffer.from('\n')) + }) + }) + + it('parses json to valid JS object', function () { + return readFile(this.projectRoot, { file: 'tests/_fixtures/users.json' }).then(({ contents }) => { + expect(contents).to.eql([ + { + id: 1, + name: 'brian', + }, { + id: 2, + name: 'jennifer', + }, + ]) + }) + }) + }) + + context('#writeFile', () => { + it('writes the file\'s contents and returns contents and full file path', function () { + return writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'foo' }).then(() => { + return readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents, filePath }) => { + expect(contents).to.equal('foo') + + expect(filePath).to.include('/cy-projects/todos/.projects/write_file.txt') + }) + }) + }) + + it('uses encoding specified in options', function () { + return writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: '', encoding: 'ascii' }).then(() => { + return readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { + expect(contents).to.equal('�') + }) + }) + }) + + // https://github.com/cypress-io/cypress/issues/1558 + it('explicit null encoding is written exactly as received', function () { + return writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: Buffer.from(''), encoding: null }).then(() => { + return readFile(this.projectRoot, { file: '.projects/write_file.txt', encoding: null }).then(({ contents }) => { + expect(contents).to.eql(Buffer.from('')) + }) + }) + }) + + it('overwrites existing file by default', function () { + return writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'foo' }).then(() => { + return readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { + expect(contents).to.equal('foo') + + return writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'bar' }).then(() => { + return readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { + expect(contents).to.equal('bar') + }) + }) + }) + }) + }) + + it('appends content to file when specified', function () { + return writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'foo' }).then(() => { + return readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { + expect(contents).to.equal('foo') + + return writeFile(this.projectRoot, { fileName: '.projects/write_file.txt', contents: 'bar', flag: 'a+' }).then(() => { + return readFile(this.projectRoot, { file: '.projects/write_file.txt' }).then(({ contents }) => { + expect(contents).to.equal('foobar') + }) + }) + }) + }) + }) + }) +}) diff --git a/packages/server/test/unit/fixture_spec.js b/packages/server/test/unit/fixture_spec.ts similarity index 92% rename from packages/server/test/unit/fixture_spec.js rename to packages/server/test/unit/fixture_spec.ts index 390c964e8ee..1a73b20f434 100644 --- a/packages/server/test/unit/fixture_spec.js +++ b/packages/server/test/unit/fixture_spec.ts @@ -1,22 +1,21 @@ -require('../spec_helper') - -const path = require('path') -const Promise = require('bluebird') -const fixture = require(`../../lib/fixture`) -const { fs } = require(`../../lib/util/fs`) -const FixturesHelper = require('@tooling/system-tests') -const snapshot = require('snap-shot-it') +import path from 'path' +import Promise from 'bluebird' +import * as fixture from '../../lib/fixture' +import { fs } from '../../lib/util/fs' +import FixturesHelper from '@tooling/system-tests' +import snapshot from 'snap-shot-it' +import { setCtx, makeDataContext, clearCtx } from '../../lib/makeDataContext' +import { getCtx } from '@packages/data-context' let ctx describe('lib/fixture', () => { before(async function () { - const { setCtx, makeDataContext, clearCtx } = require('../../lib/makeDataContext') - // Clear and set up DataContext await clearCtx() + // @ts-expect-error setCtx(makeDataContext({})) - ctx = require('../../lib/makeDataContext').getCtx() + ctx = getCtx() FixturesHelper.scaffold() @@ -24,6 +23,19 @@ describe('lib/fixture', () => { await ctx.actions.project.setCurrentProjectAndTestingTypeForTestSetup(this.todosPath) + // needed to run these tests locally + // sinon.stub(ctx.browser, 'machineBrowsers').resolves([ + // { + // channel: 'stable', + // displayName: 'Electron', + // family: 'chromium', + // majorVersion: '123', + // name: 'electron', + // path: 'path-to-browser-one', + // version: '123.45.67', + // }, + // ]) + const cfg = await ctx.lifecycleManager.getFullInitialConfig() this.fixturesFolder = cfg.fixturesFolder @@ -162,6 +174,18 @@ describe('lib/fixture', () => { // https://github.com/cypress-io/cypress/issues/3739 it('can load a fixture with no extension when a same-named folder also exists', async () => { + // needed to run these tests locally + // sinon.stub(ctx.browser, 'machineBrowsers').resolves([ + // { + // channel: 'stable', + // displayName: 'Electron', + // family: 'chromium', + // majorVersion: '123', + // name: 'electron', + // path: 'path-to-browser-one', + // version: '123.45.67', + // }, + // ]) const projectPath = FixturesHelper.projectPath('folder-same-as-fixture') await ctx.actions.project.setCurrentProjectAndTestingTypeForTestSetup(projectPath) diff --git a/packages/server/test/unit/plugins/child/run_child_fixture.js b/packages/server/test/unit/plugins/child/run_child_fixture.js index 915a67c0092..57175e7d06e 100644 --- a/packages/server/test/unit/plugins/child/run_child_fixture.js +++ b/packages/server/test/unit/plugins/child/run_child_fixture.js @@ -7,7 +7,13 @@ let proc process.on('message', (msg) => { if (msg.msg === 'spawn') { - proc = childProcess.fork(REQUIRE_ASYNC_CHILD_PATH, ['--projectRoot', msg.data.projectRoot, '--file', path.join(msg.data.projectRoot, 'cypress.config.js')]) + proc = childProcess.fork(REQUIRE_ASYNC_CHILD_PATH, ['--projectRoot', msg.data.projectRoot, '--file', path.join(msg.data.projectRoot, 'cypress.config.js')], { + env: { + // since some files are being converted to TypeScript AND we are using tsx to load the config process, we can reliably use it to load the async child here + NODE_OPTIONS: '--import tsx', + }, + }) + proc.on('message', (msg) => { process.send({ childMessage: msg }) }) diff --git a/packages/server/test/unit/status_code_spec.js b/packages/server/test/unit/status_code_spec.ts similarity index 92% rename from packages/server/test/unit/status_code_spec.js rename to packages/server/test/unit/status_code_spec.ts index 1d3f7e9f0b8..5b1c7bc2487 100644 --- a/packages/server/test/unit/status_code_spec.js +++ b/packages/server/test/unit/status_code_spec.ts @@ -1,6 +1,4 @@ -require('../spec_helper') - -const statusCode = require(`../../lib/util/status_code`) +import * as statusCode from '../../lib/util/status_code' describe('lib/util/status_code', () => { context('.isOk', () => { diff --git a/packages/server/test/unit/util/terminal_spec.js b/packages/server/test/unit/util/terminal_spec.ts similarity index 90% rename from packages/server/test/unit/util/terminal_spec.js rename to packages/server/test/unit/util/terminal_spec.ts index dc73f883a21..79a797e7d6d 100644 --- a/packages/server/test/unit/util/terminal_spec.js +++ b/packages/server/test/unit/util/terminal_spec.ts @@ -1,11 +1,9 @@ -require('../../spec_helper') - -const snapshot = require('snap-shot-it') -const stripAnsi = require('strip-ansi') -const widestLine = require('widest-line') -const env = require(`../../../lib/util/env`) -const terminal = require(`../../../lib/util/terminal`) -const terminalSize = require(`../../../lib/util/terminal-size`) +import snapshot from 'snap-shot-it' +import stripAnsi from 'strip-ansi' +import widestLine from 'widest-line' +import * as env from '../../../lib/util/env' +import * as terminal from '../../../lib/util/terminal' +import * as terminalSize from '../../../lib/util/terminal-size' const sanitizeSnapshot = (str) => { return snapshot(stripAnsi(str)) diff --git a/packages/server/test/unit/util/tty_spec.js b/packages/server/test/unit/util/tty_spec.ts similarity index 92% rename from packages/server/test/unit/util/tty_spec.js rename to packages/server/test/unit/util/tty_spec.ts index 3c918601c15..15fa97d30e3 100644 --- a/packages/server/test/unit/util/tty_spec.js +++ b/packages/server/test/unit/util/tty_spec.ts @@ -1,8 +1,6 @@ -require('../../spec_helper') - -const tty = require('tty') -const ttyUtil = require(`../../../lib/util/tty`) -const terminalSize = require(`../../../lib/util/terminal-size`) +import tty from 'tty' +import * as ttyUtil from '../../../lib/util/tty' +import * as terminalSize from '../../../lib/util/terminal-size' const ttys = [process.stdin.isTTY, process.stdout.isTTY, process.stderr.isTTY]