From 2004bc71e885d84804d6e2ce0a5bc6f074575fc2 Mon Sep 17 00:00:00 2001 From: Jupegarnica Date: Tue, 15 Nov 2022 12:15:21 +0100 Subject: [PATCH] chore: fmt --- README.md | 176 +++++++++++++++++++++++--------------------- deno.jsonc | 2 +- mod.ts | 6 +- src/cli.ts | 18 +++-- src/files.ts | 45 +++++++---- src/help.ts | 24 ++++-- src/highlight.ts | 4 +- src/print.ts | 89 ++++++++++++---------- src/runner.ts | 23 +++--- src/types.ts | 3 +- test/e2e.test.ts | 3 +- test/runner.test.ts | 44 ++++------- 12 files changed, 234 insertions(+), 203 deletions(-) diff --git a/README.md b/README.md index 7438d9f..7ee1635 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![Example demo](./.github/demo/demo.gif) - # TEPI + ### -- HTTP Test Runner-- Tepi is a test runner for .http files. @@ -9,7 +9,6 @@ Tepi is a test runner for .http files. Write your tests in .http files and run them with `tepi`. ```bash - $ cat test.http GET http://localhost:3000 # fetch a GET Request @@ -24,27 +23,25 @@ Hola mundo! # assert a body with the text "Hola mundo!" $ tepi test.http ``` - - Test your HTTP APIs with standard http syntax ## Features: -- ๐Ÿ“ Write end to end API REST tests in `.http` files -- ๐Ÿ”Ž Validate Response status, headers and/or body. -- ๐Ÿ”ฅ Interpolate javascript with eta template `<%= %>` -- ๐Ÿ–Š Write metadata as frontmatter yaml -- ๐Ÿ“ฆ Reference by name another test to run them in advance -- โฑ Set a timeout for each test or globally in milliseconds. After the timeout, the test will fail. -- ๐Ÿšจ Stop running tests after the first failure. -- ๐Ÿ”‹ Use env files to load environment variables -- ๐Ÿ˜Ž Fully featured and colorful display modes. (none, minimal, default and full) -- ๐Ÿ‘ Watch files for changes and rerun tests. -- ๐Ÿฏ Standard Response and Request with a automatic getBody() +- ๐Ÿ“ Write end to end API REST tests in `.http` files +- ๐Ÿ”Ž Validate Response status, headers and/or body. +- ๐Ÿ”ฅ Interpolate javascript with eta template `<%= %>` +- ๐Ÿ–Š Write metadata as frontmatter yaml +- ๐Ÿ“ฆ Reference by name another test to run them in advance +- โฑ Set a timeout for each test or globally in milliseconds. After the timeout, + the test will fail. +- ๐Ÿšจ Stop running tests after the first failure. +- ๐Ÿ”‹ Use env files to load environment variables +- ๐Ÿ˜Ž Fully featured and colorful display modes. (none, minimal, default and full) +- ๐Ÿ‘ Watch files for changes and rerun tests. +- ๐Ÿฏ Standard Response and Request with a automatic getBody() ## Install: - ```bash deno install --reload --unstable --allow-read --allow-env --allow-net --allow-run -f -n tepi https://tepi.deno.dev/src/cli.ts ``` @@ -61,141 +58,149 @@ tepi [OPTIONS] [FILES|GLOBS...] ## Options: -* -w `--watch` Watch files for changes and rerun tests. -* `--watch-no-clear` same but without clearing the screen. -* -t `--timeout` Set the timeout for each test in milliseconds. After the timeout, the test will fail. -* -f `--fail-fast` Stop running tests after the first failure. -* -d `--display` Set the display mode. (none, minimal, default and full) - - none: display nothing - - minimal: display only a minimal summary - - default: list results and full error summary - - full: display also all HTTP requests and responses - - verbose: display also all metadata and not truncate data -* -h `--help` output usage information -* -e `--env-file` load environment variables from a .env file -* `--no-color` output without color -* `--no-animation` output without terminal animations -* `--upgrade` upgrade to the latest version +- -w `--watch` Watch files for changes and rerun tests. +- `--watch-no-clear` same but without clearing the screen. +- -t `--timeout` Set the timeout for each test in milliseconds. After the + timeout, the test will fail. +- -f `--fail-fast` Stop running tests after the first failure. +- -d `--display` Set the display mode. (none, minimal, default and full) - none: + display nothing - minimal: display only a minimal summary - default: list + results and full error summary - full: display also all HTTP requests and + responses - verbose: display also all metadata and not truncate data +- -h `--help` output usage information +- -e `--env-file` load environment variables from a .env file +- `--no-color` output without color +- `--no-animation` output without terminal animations +- `--upgrade` upgrade to the latest version ## Examples: `tepi` + > Run all .http in the current directory and folders. (same as tepi ./**/*.http) `tepi test.http ./test2.http` + > Run test.http and test2.http `tepi **/*.http` + > Run all .http in the current directory and folders. `tepi rest.http --watch` + > Run rest.http and rerun when it changes `tepi rest.http --watch "src/**/*.ts"` + > Run rest.http and rerun when any .ts file in the src folder changes. `tepi rest.http --watch "src/**/*.json" --watch "src/**/*.ts"` -> You can use multiple --watch flags. -> Note: You can use globs here too, but use quotes to avoid the shell expanding them. + +> You can use multiple --watch flags. Note: You can use globs here too, but use +> quotes to avoid the shell expanding them. `tepi --timeout 10000` -> Set the timeout for each test in milliseconds. After the timeout, the test will fail. + +> Set the timeout for each test in milliseconds. After the timeout, the test +> will fail. `tepi --fail-fast` + > Stop running tests after the first failure. `tepi --display minimal` + > Set the display mode. (none, minimal, default and full) `tepi --env-file .env --env-file .env.test` -> Load environment variables from a .env and .env.test +> Load environment variables from a .env and .env.test ## HTTP syntax: -* You can use the standard HTTP syntax in your .http files to run a request and response validation. -* Use the `###` to separate the requests. -* Use frontmatter yaml to set metadata. +- You can use the standard HTTP syntax in your .http files to run a request and + response validation. +- Use the `###` to separate the requests. +- Use frontmatter yaml to set metadata. For example, validate the headers, status code, status text and body: ``` - GET https://faker.deno.dev/?body=hola&status=400 HTTP/1.1 400 Bad Request content-type: text/plain; charset=utf-8 hola - ``` ## Interpolation: It's deno ๐Ÿ”ฅ -Uses eta as template engine, see docs: -https://deno.land/x/eta +Uses eta as template engine, see docs: https://deno.land/x/eta Use `<%= %>` to interpolate values. All the std assertion module is available: https://deno.land/std/testing/asserts.ts - -Use `<% %>` to run custom assertions or custom JS. -For example: +Use `<% %>` to run custom assertions or custom JS. For example: ``` GET http://localhost:3000/users <% assert(response.status === 200) %> - ``` + Or: ``` - <% if (Math.random() > 0.5) { %> - GET http://localhost:3000/users/1 - <% } else { %> - GET http://localhost:3000/users/2 - <% } %> - +<% if (Math.random() > 0.5) { %> + GET http://localhost:3000/users/1 +<% } else { %> + GET http://localhost:3000/users/2 +<% } %> ``` ### Interpolation scope: -In the Interpolation `<%= %>` or `<% %>` you have access to any Deno API and the following variables: -* request: The Request from the actual block. -* meta: The metadata from the actual block. and the frontmatter global metadata. -* response: The standard Response object from the fetch API from the actual request. (only available in the expected response, after the request) -* body: The extracted body an alias of `await response.getBody()` (only available in the expected response, after the request) -* [id]: the id of a block already run for example: `<%= login.body.jwt %>` or `<%= login.response.status %>` +In the Interpolation `<%= %>` or `<% %>` you have access to any Deno API and the +following variables: + +- request: The Request from the actual block. +- meta: The metadata from the actual block. and the frontmatter global metadata. +- response: The standard Response object from the fetch API from the actual + request. (only available in the expected response, after the request) +- body: The extracted body an alias of `await response.getBody()` (only + available in the expected response, after the request) +- [id]: the id of a block already run for example: `<%= login.body.jwt %>` or + `<%= login.response.status %>` The Block signature is: ```ts type Block = { meta: { - [key: string]: any, - }, - request?: Request, - response?: Response, - expectedResponse?: Response, - error?: Error, - body?: any, -} + [key: string]: any; + }; + request?: Request; + response?: Response; + expectedResponse?: Response; + error?: Error; + body?: any; +}; ``` - -The request, response and expectedResponse has a custom method `async getBody()` to extract the body as json, text or blob depending on the content-type. +The request, response and expectedResponse has a custom method `async getBody()` +to extract the body as json, text or blob depending on the content-type. The `body` is an alias for `await response.getBody()`. For example: ``` - --- id: hello --- @@ -213,25 +218,28 @@ POST https://faker.deno.dev/ HTTP/1.1 200 OK hola - ``` ## Special metadata keys: -There are some especial metadata keys used by tepi, as: meta.needs, meta.id, meta.description, meta.display, meta.timeout and meta.import +There are some especial metadata keys used by tepi, as: meta.needs, meta.id, +meta.description, meta.display, meta.timeout and meta.import ### meta.delay: -The meta.delay allows you to delay the execution of the request fetch for a specific time in milliseconds. + +The meta.delay allows you to delay the execution of the request fetch for a +specific time in milliseconds. ### meta.timeout: -The meta.timeout allows you to override the global timeout for a specific test. -If the request takes longer than the timeout, the test will fail. -The delay is not included in the timeout. +The meta.timeout allows you to override the global timeout for a specific test. +If the request takes longer than the timeout, the test will fail. The delay is +not included in the timeout. ### meta.needs -The meta.needs is a special metadata value that allows you to run a test in advance and use the result in the current test if needed. +The meta.needs is a special metadata value that allows you to run a test in +advance and use the result in the current test if needed. For example: @@ -254,23 +262,23 @@ Content-Type: application/json {"user": "Garn", "password": "1234"} HTTP/1.1 200 OK - ``` ### meta.id and meta.description -The meta.id allows you to identify a test for reference. -The meta.description it's used to display the test name in the console if not set, it will use the meta.id. +The meta.id allows you to identify a test for reference. The meta.description +it's used to display the test name in the console if not set, it will use the +meta.id. ### meta.import: -The meta.import allows you to import a file before running the test. -The imported file will run before the file that imports it. - +The meta.import allows you to import a file before running the test. The +imported file will run before the file that imports it. ### meta.display: -The meta.display allows you to override the global display mode for a specific test. +The meta.display allows you to override the global display mode for a specific +test. For example: @@ -279,6 +287,4 @@ For example: display: verbose --- GET https://example.com/get - ``` - diff --git a/deno.jsonc b/deno.jsonc index bb80719..919f141 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -16,7 +16,7 @@ "dnt": "deno run -A https://deno.land/x/dnt_prompt/main.ts", "version": "deno run -A https://deno.land/x/version/index.ts", "readme": "deno task readme:create && NO_COLOR=1 deno run -A --unstable ./src/cli.ts --help >> README.md && git add README.md && git commit -m 'docs: update README.md' || true", - "readme:create":"echo '![Example demo](./.github/demo/demo.gif)\n' > README.md", + "readme:create": "echo '![Example demo](./.github/demo/demo.gif)\n' > README.md", "release": "deno task readme && deno task version patch && git push --tags origin main" } } diff --git a/mod.ts b/mod.ts index 986aba4..412fc1f 100644 --- a/mod.ts +++ b/mod.ts @@ -1,5 +1,5 @@ -import { cli } from './src/cli.ts'; +import { cli } from "./src/cli.ts"; if (import.meta.main) { - await cli(); -} \ No newline at end of file + await cli(); +} diff --git a/src/cli.ts b/src/cli.ts index 31294ff..97e424f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -68,7 +68,6 @@ export async function cli() { return; } - // --display ///////////// @@ -83,7 +82,8 @@ export async function cli() { if (getDisplayIndex(defaultMeta) === Infinity) { console.error( fmt.brightRed( - `Invalid display mode ${args.display}\n Must be one of: ${DISPLAYS.map((t) => fmt.bold(t)).join(", ") + `Invalid display mode ${args.display}\n Must be one of: ${ + DISPLAYS.map((t) => fmt.bold(t)).join(", ") }`, ), ); @@ -115,7 +115,8 @@ export async function cli() { if (keysLoaded.size && getDisplayIndex(defaultMeta) > 0) { console.info( fmt.gray( - `Loaded ${keysLoaded.size} environment variables from: ${Array.from(envFiles).join(", ") + `Loaded ${keysLoaded.size} environment variables from: ${ + Array.from(envFiles).join(", ") }`, ), ); @@ -125,8 +126,7 @@ export async function cli() { ///////////// const globs: string[] = args._.length ? args._ as string[] : ["**/*.http"]; - - const filePathsToRun = await globsToFilePaths(globs) + const filePathsToRun = await globsToFilePaths(globs); // runner ///////////// @@ -142,14 +142,16 @@ export async function cli() { if (getDisplayIndex(defaultMeta) > 0) { console.warn( fmt.yellow( - `\n${fmt.bgYellow(fmt.bold(" ONLY MODE ")) - } ${onlyMode.size} ${onlyMode.size === 1 ? 'test' : 'tests'} are in "only" mode.`, + `\n${fmt.bgYellow(fmt.bold(" ONLY MODE "))} ${onlyMode.size} ${ + onlyMode.size === 1 ? "test" : "tests" + } are in "only" mode.`, ), ); if (!exitCode) { console.error( fmt.red( - `Failed because the ${fmt.bold('"only"')} option was used at ${[...onlyMode].join(", ") + `Failed because the ${fmt.bold('"only"')} option was used at ${ + [...onlyMode].join(", ") }`, ), ); diff --git a/src/files.ts b/src/files.ts index 54a45aa..a168bd6 100644 --- a/src/files.ts +++ b/src/files.ts @@ -1,14 +1,21 @@ import { File } from "./types.ts"; import { Block } from "./types.ts"; - - -function shouldBeOnly(lineNumberOnly: number | undefined, blockStartLine: number, blockEndLine: number) { - const shouldBeOnly = lineNumberOnly !== undefined && lineNumberOnly >= blockStartLine && lineNumberOnly <= blockEndLine; +function shouldBeOnly( + lineNumberOnly: number | undefined, + blockStartLine: number, + blockEndLine: number, +) { + const shouldBeOnly = lineNumberOnly !== undefined && + lineNumberOnly >= blockStartLine && lineNumberOnly <= blockEndLine; return shouldBeOnly; } -export function fileTextToBlocks(txt: string, _filePath: string, lineSpec = ''): Block[] { +export function fileTextToBlocks( + txt: string, + _filePath: string, + lineSpec = "", +): Block[] { const blocks: Block[] = []; const lines = txt.replaceAll("\r", "\n").split("\n"); let currentBlockText = ""; @@ -33,7 +40,11 @@ export function fileTextToBlocks(txt: string, _filePath: string, lineSpec = ''): _startLine: blockStartLine, _endLine: blockEndLine, _filePath, - only: shouldBeOnly(lineNumberNotIgnored, blockStartLine, blockEndLine), + only: shouldBeOnly( + lineNumberNotIgnored, + blockStartLine, + blockEndLine, + ), }, }); blocks.push(block); @@ -49,8 +60,11 @@ export function fileTextToBlocks(txt: string, _filePath: string, lineSpec = ''): _startLine: blockStartLine, _endLine: blockEndLine, _filePath, - only: shouldBeOnly(lineNumberNotIgnored, blockStartLine, blockEndLine), - + only: shouldBeOnly( + lineNumberNotIgnored, + blockStartLine, + blockEndLine, + ), }, }); blocks.push(block); @@ -61,18 +75,17 @@ export function fileTextToBlocks(txt: string, _filePath: string, lineSpec = ''): import { expandGlob } from "https://deno.land/std@0.164.0/fs/mod.ts"; - -export const checkGlobHasLineSpec = (glob: string) => new RegExp(":[0-9]+").test(glob); - +export const checkGlobHasLineSpec = (glob: string) => + new RegExp(":[0-9]+").test(glob); export async function globsToFilePaths(globs: string[]): Promise { const filePaths: string[] = []; for (let glob of globs) { - let lineSpec = ''; + let lineSpec = ""; if (checkGlobHasLineSpec(glob)) { - [glob, lineSpec] = glob.split(':'); - lineSpec = ':' + lineSpec; + [glob, lineSpec] = glob.split(":"); + lineSpec = ":" + lineSpec; } for await (const fileFound of expandGlob(glob)) { if (fileFound.isFile) { @@ -89,9 +102,9 @@ export async function filePathsToFiles(filePaths: string[]): Promise { for (let _filePath of filePaths) { let fileContent = ""; - let lineSpec = ''; + let lineSpec = ""; if (checkGlobHasLineSpec(_filePath)) { - [_filePath, lineSpec] = _filePath.split(':'); + [_filePath, lineSpec] = _filePath.split(":"); } try { fileContent = await Deno.readTextFile(_filePath); diff --git a/src/help.ts b/src/help.ts index e666a01..8b549b0 100644 --- a/src/help.ts +++ b/src/help.ts @@ -34,7 +34,9 @@ ${g(`### -- HTTP Test Runner--`)} ${orange(`${fmt.bold("Tepi")} is a test runner for .http files.`)} Write your tests in .http files and run them with ${c("tepi")}. -${codeBlock(` +${ + codeBlock( + ` $ cat test.http GET http://localhost:3000 ${d(`# fetch a GET Request`)} @@ -42,12 +44,14 @@ GET http://localhost:3000 ${d(`# fetch a GET Request`)} HTTP/1.1 200 OK ${d(`# assert a 200 OK response`)} Content-Type: text/plain ${d(`# assert a text/plain content type header`)} -Hola mundo! ${d(`# assert a body with the text "Hola mundo!"`)}`, "bash")} +Hola mundo! ${d(`# assert a body with the text "Hola mundo!"`)}`, + "bash", + ) + } ${codeBlock(`$ tepi test.http`, "bash")} `; - const helpText = ` ${fmt.bold("Test your HTTP APIs with standard http syntax")} @@ -107,13 +111,17 @@ ${d(" - ")} none: ${d(`display nothing`)} ${d(" - ")} minimal: ${d(`display only a minimal summary`)} ${d(" - ")} default: ${d(`list results and full error summary`)} ${d(" - ")} full: ${d(`display also all HTTP requests and responses`)} -${d(" - ")} verbose: ${d(`display also all metadata and not truncate data`)} +${d(" - ")} verbose: ${ + d(`display also all metadata and not truncate data`) + } ${d("* ")}-h ${c("--help")} ${d("output usage information")} ${d("* ")}-e ${c("--env-file")} ${ d("load environment variables from a .env file") } ${d("* ")} ${c("--no-color")} ${d("output without color")} -${d("* ")} ${c("--no-animation")} ${d("output without terminal animations")} +${d("* ")} ${c("--no-animation")} ${ + d("output without terminal animations") + } ${d("* ")} ${c("--upgrade")} ${d("upgrade to the latest version")} ${g("## Examples:")} @@ -341,8 +349,8 @@ GET https://example.com/get } `; - console.info(title ); - console.info( helpText); - console.info( referenceText); + console.info(title); + console.info(helpText); + console.info(referenceText); return; } diff --git a/src/highlight.ts b/src/highlight.ts index b1b1854..78ae847 100644 --- a/src/highlight.ts +++ b/src/highlight.ts @@ -4,7 +4,9 @@ let supportsLang = (_: string) => true; let hl = (code: string, { language: _ }: { language: string }) => code; try { - const { highlight, supportsLanguage } = await import("npm:cli-highlight@2.1.11"); + const { highlight, supportsLanguage } = await import( + "npm:cli-highlight@2.1.11" + ); hl = highlight; supportsLang = supportsLanguage; } catch { diff --git a/src/print.ts b/src/print.ts index 426dfa8..0e1c653 100644 --- a/src/print.ts +++ b/src/print.ts @@ -9,7 +9,6 @@ import { ms } from "https://deno.land/x/ms@v0.1.0/ms.ts"; type FmtMethod = keyof typeof fmt; const REFRESH_INTERVAL = 130; - function consoleSize(): { rows: number; columns: number } { try { const { columns, rows } = Deno.consoleSize(); @@ -27,8 +26,9 @@ function printTitle(title: string, fmtMethod: FmtMethod = "gray") { let padLength = 2 + Math.floor((consoleWidth - titleStr.length) / 2); padLength = padLength < 0 ? 0 : padLength; const separator = fmt.gray("-"); - const output = `${separator.repeat(5)} ${titleStr} ${separator.repeat(padLength) - }`; + const output = `${separator.repeat(5)} ${titleStr} ${ + separator.repeat(padLength) + }`; console.info(output); } @@ -51,7 +51,6 @@ export function getDisplayIndex(meta: Meta): number { export async function printBlock(block: Block): Promise { const { request, actualResponse, expectedResponse, error, meta } = block; - const displayIndex = getDisplayIndex(meta); if (displayIndex < 3) { return; @@ -64,8 +63,9 @@ export async function printBlock(block: Block): Promise { block.meta._relativeFilePath && (request || actualResponse || expectedResponse || error) ) { - const path = `\n${fmt.dim("Data from:")} ${fmt.cyan(`${block.meta._relativeFilePath}:${block.meta._startLine}`) - }`; + const path = `\n${fmt.dim("Data from:")} ${ + fmt.cyan(`${block.meta._relativeFilePath}:${block.meta._startLine}`) + }`; console.info(path); } if (meta && displayIndex >= 4) { @@ -142,9 +142,10 @@ export function printErrorsSummary(_blocks: Set): void { firstError || console.error(fmt.dim("------------------")); if (getDisplayIndex(meta) === 1) { // minimal - const descriptionMaybeTruncated = (description.length > maximumLength - 20) - ? `${description.slice(0, maximumLength - 20)}...` - : description; + const descriptionMaybeTruncated = + (description.length > maximumLength - 20) + ? `${description.slice(0, maximumLength - 20)}...` + : description; const messageText = fmt.stripColor( `${descriptionMaybeTruncated} => ${error.name}: ${error.message}`, @@ -161,13 +162,15 @@ export function printErrorsSummary(_blocks: Set): void { message = `${fmt.red("โœ–")} ${finalMsg} ${messagePath}`; } else { // default - message = `${fmt.red("โœ–")} ${fmt.red(description + " => ")} ${fmt.bold(error.name) - }\n${fmt.white(error.message)} \n${messagePath}`; + message = `${fmt.red("โœ–")} ${fmt.red(description + " => ")} ${ + fmt.bold(error.name) + }\n${fmt.white(error.message)} \n${messagePath}`; } } else { // already displayed - message = `${fmt.red(description + " => ")} ${fmt.bold(error.name).padEnd(maximumLength) - } ${messagePath}`; + message = `${fmt.red(description + " => ")} ${ + fmt.bold(error.name).padEnd(maximumLength) + } ${messagePath}`; } console.error(message); firstError = false; @@ -208,10 +211,10 @@ export function responseToText(response: Response): string { const statusColor = response.status >= 200 && response.status < 300 ? fmt.green : response.status >= 300 && response.status < 400 - ? fmt.yellow - : response.status >= 400 && response.status < 500 - ? fmt.red - : fmt.bgRed; + ? fmt.yellow + : response.status >= 400 && response.status < 500 + ? fmt.red + : fmt.bgRed; const status = statusColor(String(response.status)); const statusText = response.statusText; @@ -253,8 +256,9 @@ export function headersToText(headers: Headers, displayIndex: number): string { maxLengthKey = Math.max(maxLengthKey, truncate(key, truncateAt).length); } for (const [key, value] of headers.entries()) { - result += `${fmt.gray(`${truncate(key, truncateAt)}:`.padEnd(maxLengthKey + 1)) - } ${fmt.dim(truncate(value, truncateAt))}\n`; + result += `${ + fmt.gray(`${truncate(key, truncateAt)}:`.padEnd(maxLengthKey + 1)) + } ${fmt.dim(truncate(value, truncateAt))}\n`; } return result; @@ -332,7 +336,11 @@ const log = (text: string, prefix?: string) => // discardStdin: true, }).start(); -export const logPath = (text: string, displayIndex: number, noAnimation = false) => { +export const logPath = ( + text: string, + displayIndex: number, + noAnimation = false, +) => { if (displayIndex === 1) { return noAnimation ? console.info(text) : log(text); } @@ -341,7 +349,6 @@ export const logPath = (text: string, displayIndex: number, noAnimation = false) } }; - export type BlockSpinner = { fail: () => void; ignore: () => void; @@ -378,8 +385,9 @@ export function createBlockSpinner( ? fmt.dim(` needed -> ${fromFilePath}`) : ""; const startTime = Date.now(); - const text = `${block.description} ${" "} ${fmt.gray("0ms") - }${differentFile}`; + const text = `${block.description} ${" "} ${ + fmt.gray("0ms") + }${differentFile}`; const spinner = wait({ prefix: "", @@ -395,8 +403,9 @@ export function createBlockSpinner( return; } const _elapsedTime = Date.now() - startTime; - const text = `${fmt.brightWhite(block.description)} ${" "} ${fmt.gray(`${(_elapsedTime)}ms`) - }${differentFile}`; + const text = `${fmt.brightWhite(block.description)} ${" "} ${ + fmt.gray(`${(_elapsedTime)}ms`) + }${differentFile}`; if (text !== spinner.text) { spinner.text = text; } @@ -417,13 +426,14 @@ export function createBlockSpinner( block.meta._elapsedTime = _elapsedTime; const status = String(block.actualResponse?.status || ""); const statusText = status ? (" " + status) : (" ERR"); - const text = `${fmt.red(block.description)} ${statusText} ${fmt.gray(`${ms(_elapsedTime)}`) - }${differentFile}`; + const text = `${fmt.red(block.description)} ${statusText} ${ + fmt.gray(`${ms(_elapsedTime)}`) + }${differentFile}`; const symbol = fmt.brightRed("โœ–"); clearInterval(id); if (globalMeta._noAnimation) { - console.info(symbol, text) + console.info(symbol, text); return; } spinner.stopAndPersist({ @@ -434,13 +444,14 @@ export function createBlockSpinner( ignore: () => { const _elapsedTime = Date.now() - startTime; - const text = `${fmt.yellow(block.description)} ${" "} ${fmt.gray(`${ms(_elapsedTime)}`) - }${differentFile}`; - const symbol = fmt.yellow("ยท") + const text = `${fmt.yellow(block.description)} ${" "} ${ + fmt.gray(`${ms(_elapsedTime)}`) + }${differentFile}`; + const symbol = fmt.yellow("ยท"); clearInterval(id); if (globalMeta._noAnimation) { - console.info(symbol, text) + console.info(symbol, text); return; } spinner.stopAndPersist({ @@ -452,13 +463,14 @@ export function createBlockSpinner( const _elapsedTime = Date.now() - startTime; block.meta._elapsedTime = _elapsedTime; const status = String(block.actualResponse?.status); - const text = `${fmt.green(block.description)} ${status} ${fmt.gray(`${ms(_elapsedTime)}`) - }${differentFile}`; + const text = `${fmt.green(block.description)} ${status} ${ + fmt.gray(`${ms(_elapsedTime)}`) + }${differentFile}`; const symbol = fmt.brightGreen("โœ”"); clearInterval(id); if (globalMeta._noAnimation) { - console.info(symbol, text) + console.info(symbol, text); return; } @@ -476,12 +488,13 @@ export function createBlockSpinner( }, empty: () => { const _elapsedTime = Date.now() - startTime; - const text = `${fmt.dim(block.description)} ${" "} ${fmt.gray(`${ms(_elapsedTime)}`) - }${differentFile}`; + const text = `${fmt.dim(block.description)} ${" "} ${ + fmt.gray(`${ms(_elapsedTime)}`) + }${differentFile}`; const symbol = fmt.dim("ยท"); clearInterval(id); if (globalMeta._noAnimation) { - console.info(symbol, text) + console.info(symbol, text); return; } diff --git a/src/runner.ts b/src/runner.ts index ff8f971..e630f19 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -10,8 +10,8 @@ import { resolve, } from "https://deno.land/std@0.164.0/path/posix.ts"; import { - getDisplayIndex, createBlockSpinner, + getDisplayIndex, logPath, printBlock, printErrorsSummary, @@ -24,8 +24,6 @@ import { } from "./parser.ts"; import * as assertions from "https://deno.land/std@0.164.0/testing/asserts.ts"; - - export async function runner( filePaths: string[], defaultMeta: Meta, @@ -136,10 +134,12 @@ export async function runner( pathSpinner?.clear(); } - const totalBlockRun = successfulBlocks + failedBlocks ; + const totalBlockRun = successfulBlocks + failedBlocks; const exitCode = failedBlocks > 0 ? failedBlocks - : totalBlockRun === 0 ? 1 : 0; + : totalBlockRun === 0 + ? 1 + : 0; if (getDisplayIndex(defaultMeta) !== 0) { printErrorsSummary(blocksDone); @@ -154,8 +154,10 @@ export async function runner( console.info(); console.info( fmt.bold(`${statusText}`), - `${fmt.white(String(totalBlocks))} tests, ${fmt.green(String(successfulBlocks)) - } passed, ${fmt.red(String(failedBlocks))} failed, ${fmt.yellow(String(ignoredBlocks)) + `${fmt.white(String(totalBlocks))} tests, ${ + fmt.green(String(successfulBlocks)) + } passed, ${fmt.red(String(failedBlocks))} failed, ${ + fmt.yellow(String(ignoredBlocks)) } ignored ${prettyGlobalTime}`, ); } @@ -248,7 +250,6 @@ async function runBlock( return blocksDone; } - if (!block.request) { if (block.meta._isFirstBlock) { spinner.clear(); @@ -260,7 +261,6 @@ async function runBlock( return blocksDone; } - if (block.error) { throw block.error; } @@ -338,7 +338,9 @@ async function processMetadata( ...meta, }; if (block.meta.only) { - onlyMode.add(`${block.meta._relativeFilePath}:${block.meta._startLine}`); + onlyMode.add( + `${block.meta._relativeFilePath}:${block.meta._startLine}`, + ); } if (block.meta.import) { if (isAbsolute(block.meta.import)) { @@ -347,7 +349,6 @@ async function processMetadata( mustBeImported.add(resolve(dirname(file.path), block.meta.import)); } } - } catch (error) { error.message = `Error parsing metadata: ${error.message}`; block.error = error; diff --git a/src/types.ts b/src/types.ts index d77b0fe..5094431 100644 --- a/src/types.ts +++ b/src/types.ts @@ -96,8 +96,7 @@ export class Block { return String(this.meta.description); } if (this.meta.id) { - return String(this.meta.id) - + return String(this.meta.id); } if (this.request) { return `${this.request.method} ${this.request.url}`; diff --git a/test/e2e.test.ts b/test/e2e.test.ts index 66e198b..f68d198 100644 --- a/test/e2e.test.ts +++ b/test/e2e.test.ts @@ -19,14 +19,13 @@ async function run(command: string) { const tepi = "deno run -A --unstable ./src/cli.ts "; Deno.test("[e2e] must return code 0 when all tests pass", async () => { - const { code, out, success } = await run(tepi + "http/pass.http"); + const { code, out, success } = await run(tepi + "http/pass.http"); assert(out.length > 0); assertEquals(code, 0); assertEquals(success, true); // assertEquals(err, ""); }); - Deno.test("[e2e] must return the code of failing tests", async () => { const { code } = await run(tepi + "http/failFast.http"); assertEquals(code, 2); diff --git a/test/runner.test.ts b/test/runner.test.ts index a489c9f..13fc918 100644 --- a/test/runner.test.ts +++ b/test/runner.test.ts @@ -201,8 +201,6 @@ Deno.test( }, ); - - Deno.test( "[runner] only mode do not ignore needed blocks", async () => { @@ -216,14 +214,13 @@ Deno.test( assertEquals(blocks[0].meta.ignore, true); assertEquals(blocks[1].meta.ignore, true); - assertEquals(blocks[2].description, 'no ignored'); + assertEquals(blocks[2].description, "no ignored"); assertEquals(blocks[2].meta.ignore, false); - assertEquals(blocks[3].meta.needs, 'no ignored'); + assertEquals(blocks[3].meta.needs, "no ignored"); }, ); - Deno.test( "[runner] only mode do not fail parse request if the block is ignored", async () => { @@ -238,11 +235,9 @@ Deno.test( assertEquals(blocks[3].meta.ignore, true); assertEquals(blocks[3].error, undefined); assertEquals(exitCode, 0); - }, ); - Deno.test( "[runner] global vars", async () => { @@ -422,8 +417,6 @@ Deno.test( }, ); - - Deno.test( "[runner] run a line than needs another block", async () => { @@ -433,12 +426,12 @@ Deno.test( display: "none", }); const blockInOrder = [...blocksDone]; - assertEquals(blockInOrder[1].description, '404'); + assertEquals(blockInOrder[1].description, "404"); assertEquals(blockInOrder[1].meta.only, false); assertEquals(blockInOrder[1].meta.ignore, false); assertEquals(blockInOrder[1].meta._isSuccessfulBlock, true); - assertEquals(blockInOrder[2].description, 'needs404'); + assertEquals(blockInOrder[2].description, "needs404"); assertEquals(blockInOrder[2].meta._isSuccessfulBlock, true); assertEquals(blockInOrder[2].meta.only, true); assertEquals(blockInOrder[2].meta.ignore, undefined); @@ -449,7 +442,6 @@ Deno.test( }, ); - Deno.test( "[runner] run a line than does not need another block", async () => { @@ -459,16 +451,16 @@ Deno.test( display: "none", }); const blockInOrder = [...blocksDone]; - assertEquals(blockInOrder[1].description, 'needs404'); + assertEquals(blockInOrder[1].description, "needs404"); assertEquals(blockInOrder[1].meta._isIgnoredBlock, true); assertEquals(blockInOrder[1].meta.only, false); - assertEquals(blockInOrder[2].description, '404'); + assertEquals(blockInOrder[2].description, "404"); assertEquals(blockInOrder[2].meta._isSuccessfulBlock, undefined); assertEquals(blockInOrder[2].meta._isIgnoredBlock, true); assertEquals(blockInOrder[2].meta.only, false); - assertEquals(blockInOrder[3].description, '400'); + assertEquals(blockInOrder[3].description, "400"); assertEquals(blockInOrder[3].meta._isIgnoredBlock, undefined); assertEquals(blockInOrder[3].meta.only, true); assertEquals(blockInOrder[3].meta._isSuccessfulBlock, true); @@ -476,16 +468,12 @@ Deno.test( }, ); - - -Deno.test("[runner] must fail if no test has been run", - async () => { - const { exitCode } = await runner([ - Deno.cwd() + "/http/noTests.http", - ], { - display: "none", - }); - assertEquals(exitCode, 1); - // console.log([...blocksDone].map((b) => b.meta._isFetchedBlock)); - - }); \ No newline at end of file +Deno.test("[runner] must fail if no test has been run", async () => { + const { exitCode } = await runner([ + Deno.cwd() + "/http/noTests.http", + ], { + display: "none", + }); + assertEquals(exitCode, 1); + // console.log([...blocksDone].map((b) => b.meta._isFetchedBlock)); +});