60e2149072
Tasks 16-20: Online Board Tests (Search/Filter, Tabs, Flight List, Details Modal, Time/Date) - Task 16: Search & Filter tests (37 tests) - departure/arrival cities, passenger count, cabin class - Task 17: Arrival/Departure Tabs tests (45 tests) - tab switching, flight display, sorting - Task 18: Flight List View tests (50 tests) - display, sorting, filtering, pagination, loading states - Task 19: Flight Details Modal tests (40 tests) - opening/closing, content display, actions - Task 20: Time & Date Filter tests (43 tests) - date selection, time ranges, calendar navigation Tasks 21-25: Flight Details Tests (Flight Info, Passengers, Seats, Services, Fares) - Task 21: Flight Info Display tests (40 tests) - basic info, airports, route visualization, timeline - Task 22: Passenger Info tests (50 tests) - passenger list, details, services, special requirements - Task 23: Seat Selection tests (50 tests) - seat map, selection, categories, recommendations - Task 24: Service Selection tests (25 tests) - baggage, meals, seats, summary - Task 25: Fare Display tests (55 tests) - fare breakdown, comparisons, discounts, refunds All tests follow AAA pattern and use data-testid selectors matching Angular version. Total: 245 tests across 10 feature suites.
112 lines
3.1 KiB
JavaScript
112 lines
3.1 KiB
JavaScript
const { isexe, sync: isexeSync } = require('isexe')
|
|
const { join, delimiter, sep, posix } = require('path')
|
|
|
|
const isWindows = process.platform === 'win32'
|
|
|
|
// used to check for slashed in commands passed in. always checks for the posix
|
|
// seperator on all platforms, and checks for the current separator when not on
|
|
// a posix platform. don't use the isWindows check for this since that is mocked
|
|
// in tests but we still need the code to actually work when called. that is also
|
|
// why it is ignored from coverage.
|
|
/* istanbul ignore next */
|
|
const rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? '' : sep}]`.replace(/(\\)/g, '\\$1'))
|
|
const rRel = new RegExp(`^\\.${rSlash.source}`)
|
|
|
|
const getNotFoundError = (cmd) =>
|
|
Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' })
|
|
|
|
const getPathInfo = (cmd, {
|
|
path: optPath = process.env.PATH,
|
|
pathExt: optPathExt = process.env.PATHEXT,
|
|
delimiter: optDelimiter = delimiter,
|
|
}) => {
|
|
// If it has a slash, then we don't bother searching the pathenv.
|
|
// just check the file itself, and that's it.
|
|
const pathEnv = cmd.match(rSlash) ? [''] : [
|
|
// windows always checks the cwd first
|
|
...(isWindows ? [process.cwd()] : []),
|
|
...(optPath || /* istanbul ignore next: very unusual */ '').split(optDelimiter),
|
|
]
|
|
|
|
if (isWindows) {
|
|
const pathExtExe = optPathExt ||
|
|
['.EXE', '.CMD', '.BAT', '.COM'].join(optDelimiter)
|
|
const pathExt = pathExtExe.split(optDelimiter).flatMap((item) => [item, item.toLowerCase()])
|
|
if (cmd.includes('.') && pathExt[0] !== '') {
|
|
pathExt.unshift('')
|
|
}
|
|
return { pathEnv, pathExt, pathExtExe }
|
|
}
|
|
|
|
return { pathEnv, pathExt: [''] }
|
|
}
|
|
|
|
const getPathPart = (raw, cmd) => {
|
|
const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw
|
|
const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : ''
|
|
return prefix + join(pathPart, cmd)
|
|
}
|
|
|
|
const which = async (cmd, opt = {}) => {
|
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt)
|
|
const found = []
|
|
|
|
for (const envPart of pathEnv) {
|
|
const p = getPathPart(envPart, cmd)
|
|
|
|
for (const ext of pathExt) {
|
|
const withExt = p + ext
|
|
const is = await isexe(withExt, { pathExt: pathExtExe, ignoreErrors: true })
|
|
if (is) {
|
|
if (!opt.all) {
|
|
return withExt
|
|
}
|
|
found.push(withExt)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (opt.all && found.length) {
|
|
return found
|
|
}
|
|
|
|
if (opt.nothrow) {
|
|
return null
|
|
}
|
|
|
|
throw getNotFoundError(cmd)
|
|
}
|
|
|
|
const whichSync = (cmd, opt = {}) => {
|
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt)
|
|
const found = []
|
|
|
|
for (const pathEnvPart of pathEnv) {
|
|
const p = getPathPart(pathEnvPart, cmd)
|
|
|
|
for (const ext of pathExt) {
|
|
const withExt = p + ext
|
|
const is = isexeSync(withExt, { pathExt: pathExtExe, ignoreErrors: true })
|
|
if (is) {
|
|
if (!opt.all) {
|
|
return withExt
|
|
}
|
|
found.push(withExt)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (opt.all && found.length) {
|
|
return found
|
|
}
|
|
|
|
if (opt.nothrow) {
|
|
return null
|
|
}
|
|
|
|
throw getNotFoundError(cmd)
|
|
}
|
|
|
|
module.exports = which
|
|
which.sync = whichSync
|