mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 07:44:48 -05:00
2c7174a5a2
Closes #17831. This change hides the indices of any indexed collection when triggering tab completion for object properties in the REPL. An example is shown in the issue, but for verbosity here is another. Before the change: ``` > const arr = new Uint8ClampedArray([1, 2, 3]) undefined > arr. 0 map 1 reverse 2 reduce ... ``` After the change: ``` > const arr = new Uint8ClampedArray([1, 2, 3]) undefined > arr. constructor reduce BYTES_PER_ELEMENT reduceRight buffer set ... ``` Co-authored-by: David Sherret <dsherret@users.noreply.github.com>
1075 lines
26 KiB
Rust
1075 lines
26 KiB
Rust
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use test_util as util;
|
|
use test_util::assert_contains;
|
|
use test_util::assert_ends_with;
|
|
use test_util::assert_not_contains;
|
|
use util::TempDir;
|
|
|
|
#[ignore]
|
|
#[test]
|
|
fn pty_multiline() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("(\n1 + 2\n)");
|
|
console.write_line("{\nfoo: \"foo\"\n}");
|
|
console.write_line("`\nfoo\n`");
|
|
console.write_line("`\n\\`\n`");
|
|
console.write_line("'{'");
|
|
console.write_line("'('");
|
|
console.write_line("'['");
|
|
console.write_line("/{/");
|
|
console.write_line("/\\(/");
|
|
console.write_line("/\\[/");
|
|
console.write_line("console.log(\"{test1} abc {test2} def {{test3}}\".match(/{([^{].+?)}/));");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, '3');
|
|
assert_contains!(output, "{ foo: \"foo\" }");
|
|
assert_contains!(output, "\"\\nfoo\\n\"");
|
|
assert_contains!(output, "\"\\n`\\n\"");
|
|
assert_contains!(output, "\"{\"");
|
|
assert_contains!(output, "\"(\"");
|
|
assert_contains!(output, "\"[\"");
|
|
assert_contains!(output, "/{/");
|
|
assert_contains!(output, "/\\(/");
|
|
assert_contains!(output, "/\\[/");
|
|
assert_contains!(output, "[ \"{test1}\", \"test1\" ]");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_null() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("null");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "null");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_unpaired_braces() {
|
|
for right_brace in &[")", "]", "}"] {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line(right_brace);
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "Expression expected");
|
|
});
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pty_bad_input() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("'\\u{1f3b5}'[0]");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "Unterminated string literal");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_syntax_error_input() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("('\\u')");
|
|
console.write_line("'");
|
|
console.write_line("[{'a'}];");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(
|
|
output,
|
|
"Bad character escape sequence, expected 4 hex characters"
|
|
);
|
|
assert_contains!(output, "Unterminated string constant");
|
|
assert_contains!(output, "Expected a semicolon");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_symbol() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("Symbol.it\t");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "Symbol(Symbol.iterator)");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_declarations() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("class MyClass {}");
|
|
console.write_line("My\t");
|
|
console.write_line("let myVar;");
|
|
console.write_line("myV\t");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "> MyClass");
|
|
assert_contains!(output, "> myVar");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_primitives() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("let func = function test(){}");
|
|
console.write_line("func.appl\t");
|
|
console.write_line("let str = ''");
|
|
console.write_line("str.leng\t");
|
|
console.write_line("false.valueO\t");
|
|
console.write_line("5n.valueO\t");
|
|
console.write_line("let num = 5");
|
|
console.write_line("num.toStrin\t");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "> func.apply");
|
|
assert_contains!(output, "> str.length");
|
|
assert_contains!(output, "> 5n.valueOf");
|
|
assert_contains!(output, "> false.valueOf");
|
|
assert_contains!(output, "> num.toString");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_expression() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_text("Deno.\t\t");
|
|
console.write_text("y");
|
|
console.write_line("");
|
|
console.write_line("close();");
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "Display all");
|
|
assert_contains!(output, "args");
|
|
assert_contains!(output, "exit");
|
|
assert_contains!(output, "symlink");
|
|
assert_contains!(output, "permissions");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_imports() {
|
|
util::with_pty(&["repl", "-A"], |mut console| {
|
|
// single quotes
|
|
console.write_line("import './run/001_hel\t'");
|
|
// double quotes
|
|
console.write_line("import { output } from \"./run/045_out\t\"");
|
|
console.write_line("output('testing output');");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "Hello World");
|
|
assert_contains!(
|
|
output,
|
|
// on windows, could any (it's flaky)
|
|
"\ntesting output",
|
|
"testing output\u{1b}",
|
|
"\r\n\u{1b}[?25htesting output",
|
|
);
|
|
});
|
|
|
|
// ensure when the directory changes that the suggestions come from the cwd
|
|
util::with_pty(&["repl", "-A"], |mut console| {
|
|
console.write_line("Deno.chdir('./subdir');");
|
|
console.write_line("import '../run/001_hel\t'");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "Hello World");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_imports_no_panic_empty_specifier() {
|
|
// does not panic when tabbing when empty
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("import '\t';");
|
|
console.write_line("close();");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_ignore_symbols() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("Array.Symbol\t");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "undefined");
|
|
assert_not_contains!(
|
|
output,
|
|
"Uncaught TypeError: Array.Symbol is not a function"
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_assign_global_this() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("globalThis = 42;");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_not_contains!(output, "panicked");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_assign_deno_keys_and_deno() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line(
|
|
"Object.keys(Deno).forEach((key)=>{try{Deno[key] = undefined} catch {}})",
|
|
);
|
|
console.write_line("delete globalThis.Deno");
|
|
console.write_line("console.log('testing ' + 'this out')");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
assert_not_contains!(output, "panicked");
|
|
assert_contains!(output, "testing this out");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_internal_repl() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("globalThis");
|
|
console.write_line("__\t\t");
|
|
console.write_line("close();");
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "__defineGetter__");
|
|
// should not contain the internal repl variable
|
|
// in the `globalThis` or completions output
|
|
assert_not_contains!(output, "__DENO_");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_emoji() {
|
|
// windows was having issues displaying this
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line(r#"console.log('\u{1F995}');"#);
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
// only one for the output (since input is escaped)
|
|
let emoji_count = output.chars().filter(|c| *c == '🦕').count();
|
|
assert_eq!(emoji_count, 1);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn console_log() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["console.log('hello')", "'world'"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "hello\nundefined\n\"world\"\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn object_literal() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["{}", "{ foo: 'bar' }"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "{}\n{ foo: \"bar\" }\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn block_expression() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["{};", "{\"\"}"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "undefined\n\"\"\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn await_resolve() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["await Promise.resolve('done')"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "\"done\"\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn await_timeout() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["await new Promise((r) => setTimeout(r, 0, 'done'))"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "\"done\"\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn let_redeclaration() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["let foo = 0;", "foo", "let foo = 1;", "foo"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "undefined\n0\nundefined\n1\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn repl_cwd() {
|
|
let (_out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["Deno.cwd()"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn typescript() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![
|
|
"function add(a: number, b: number) { return a + b }",
|
|
"const result: number = add(1, 2) as number;",
|
|
"result",
|
|
]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "undefined\nundefined\n3\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn typescript_declarations() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![
|
|
"namespace Test { export enum Values { A, B, C } }",
|
|
"Test.Values.A",
|
|
"Test.Values.C",
|
|
"interface MyInterface { prop: string; }",
|
|
"type MyTypeAlias = string;",
|
|
]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
let expected_end_text = "undefined\n0\n2\nundefined\nundefined\n";
|
|
assert_ends_with!(out, expected_end_text);
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn typescript_decorators() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![
|
|
"function dec(target) { target.prototype.test = () => 2; }",
|
|
"@dec class Test {}",
|
|
"new Test().test()",
|
|
]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "undefined\n[Class: Test]\n2\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn eof() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["1 + 2"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "3\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn strict() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![
|
|
"let a = {};",
|
|
"Object.preventExtensions(a);",
|
|
"a.c = 1;",
|
|
]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(
|
|
out,
|
|
"Uncaught TypeError: Cannot add property c, object is not extensible"
|
|
);
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn close_command() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["close()", "'ignored'"]),
|
|
None,
|
|
false,
|
|
);
|
|
|
|
assert_not_contains!(out, "ignored");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn function() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["Deno.writeFileSync"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "[Function: writeFileSync]\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn multiline() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["(\n1 + 2\n)"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "3\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn import() {
|
|
let (out, _) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec![],
|
|
Some(vec!["import('./subdir/auto_print_hello.ts')"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_contains!(out, "hello!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn import_declarations() {
|
|
let (out, _) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--allow-read"],
|
|
Some(vec!["import './subdir/auto_print_hello.ts';"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_contains!(out, "hello!\n");
|
|
}
|
|
|
|
#[test]
|
|
fn exports_stripped() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["export default 5;", "export class Test {}"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_contains!(out, "5\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn call_eval_unterminated() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["eval('{')"]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "Unexpected end of input");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn unpaired_braces() {
|
|
for right_brace in &[")", "]", "}"] {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![right_brace]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "Expression expected");
|
|
assert!(err.is_empty());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn reference_error() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["not_a_variable"]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "not_a_variable is not defined");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn syntax_error() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![
|
|
"syntax error",
|
|
"2", // ensure it keeps accepting input after
|
|
]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "parse error: Expected ';', '}' or <eof> at 1:8\n2\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn syntax_error_jsx() {
|
|
// JSX is not supported in the REPL
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["const element = <div />;"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_contains!(out, "Expression expected");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn type_error() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["console()"]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "console is not a function");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn variable() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["var a = 123;", "a"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "undefined\n123\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn lexical_scoped_variable() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["let a = 123;", "a"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "undefined\n123\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn missing_deno_dir() {
|
|
use std::fs::read_dir;
|
|
let temp_dir = TempDir::new();
|
|
let deno_dir_path = temp_dir.path().join("deno");
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["1"]),
|
|
Some(vec![
|
|
(
|
|
"DENO_DIR".to_owned(),
|
|
deno_dir_path.to_str().unwrap().to_owned(),
|
|
),
|
|
("NO_COLOR".to_owned(), "1".to_owned()),
|
|
]),
|
|
false,
|
|
);
|
|
assert!(read_dir(deno_dir_path).is_ok());
|
|
assert_ends_with!(out, "1\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn custom_history_path() {
|
|
use std::fs::read;
|
|
let temp_dir = TempDir::new();
|
|
let history_path = temp_dir.path().join("history.txt");
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["1"]),
|
|
Some(vec![
|
|
(
|
|
"DENO_REPL_HISTORY".to_owned(),
|
|
history_path.to_str().unwrap().to_owned(),
|
|
),
|
|
("NO_COLOR".to_owned(), "1".to_owned()),
|
|
]),
|
|
false,
|
|
);
|
|
assert!(read(&history_path).is_ok());
|
|
assert_ends_with!(out, "1\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn disable_history_file() {
|
|
let deno_dir = util::new_deno_dir();
|
|
let default_history_path = deno_dir.path().join("deno_history.txt");
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["1"]),
|
|
Some(vec![
|
|
(
|
|
"DENO_DIR".to_owned(),
|
|
deno_dir.path().to_str().unwrap().to_owned(),
|
|
),
|
|
("DENO_REPL_HISTORY".to_owned(), "".to_owned()),
|
|
("NO_COLOR".to_owned(), "1".to_owned()),
|
|
]),
|
|
false,
|
|
);
|
|
assert!(!default_history_path.try_exists().unwrap());
|
|
assert_ends_with!(out, "1\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn save_last_eval() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["1", "_"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "1\n1\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn save_last_thrown() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["throw 1", "_error"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(out, "Uncaught 1\n1\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn assign_underscore() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["_ = 1", "2", "_"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert_ends_with!(
|
|
out,
|
|
"Last evaluation result is no longer saved to _.\n1\n2\n1\n"
|
|
);
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn assign_underscore_error() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["_error = 1", "throw 2", "_error"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
println!("{out}");
|
|
assert_ends_with!(
|
|
out,
|
|
"Last thrown error is no longer saved to _error.\n1\nUncaught 2\n1\n"
|
|
);
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn custom_inspect() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![
|
|
r#"const o = {
|
|
[Symbol.for("Deno.customInspect")]() {
|
|
throw new Error('Oops custom inspect error');
|
|
},
|
|
};"#,
|
|
"o",
|
|
]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
|
|
assert_contains!(out, "Oops custom inspect error");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn eval_flag_valid_input() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--eval", "const t = 10;"],
|
|
Some(vec!["t * 500;"]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "5000");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn eval_flag_parse_error() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--eval", "const %"],
|
|
Some(vec!["250 * 10"]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(
|
|
test_util::strip_ansi_codes(&out),
|
|
"Error in --eval flag: parse error: Unexpected token `%`."
|
|
);
|
|
assert_contains!(out, "2500"); // should not prevent input
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn eval_flag_runtime_error() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--eval", "throw new Error('Testing')"],
|
|
Some(vec!["250 * 10"]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "Error in --eval flag: Uncaught Error: Testing");
|
|
assert_contains!(out, "2500"); // should not prevent input
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn eval_file_flag_valid_input() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--eval-file=./run/001_hello.js"],
|
|
None,
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "Hello World");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn eval_file_flag_call_defined_function() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--eval-file=./tsc/d.ts"],
|
|
Some(vec!["v4()"]),
|
|
None,
|
|
false,
|
|
);
|
|
assert_contains!(out, "hello");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn eval_file_flag_http_input() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--eval-file=http://127.0.0.1:4545/tsc/d.ts"],
|
|
Some(vec!["v4()"]),
|
|
None,
|
|
true,
|
|
);
|
|
assert_contains!(out, "hello");
|
|
assert!(err.contains("Download"));
|
|
}
|
|
|
|
#[test]
|
|
fn eval_file_flag_multiple_files() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--allow-read", "--eval-file=http://127.0.0.1:4545/repl/import_type.ts,./tsc/d.ts,http://127.0.0.1:4545/type_definitions/foo.js"],
|
|
Some(vec!["b.method1=v4", "b.method1()+foo.toUpperCase()"]),
|
|
None,
|
|
true,
|
|
);
|
|
assert_contains!(out, "helloFOO");
|
|
assert_contains!(err, "Download");
|
|
}
|
|
|
|
#[test]
|
|
fn pty_clear_function() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("console.log('hello');");
|
|
console.write_line("clear();");
|
|
console.write_line("const clear = 1234 + 2000;");
|
|
console.write_line("clear;");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
if cfg!(windows) {
|
|
// Windows will overwrite what's in the console buffer before
|
|
// we read from it. It contains this string repeated many times
|
|
// to clear the screen.
|
|
assert_contains!(output, "\r\n\u{1b}[K\r\n\u{1b}[K\r\n\u{1b}[K");
|
|
} else {
|
|
assert_contains!(output, "hello");
|
|
assert_contains!(output, "[1;1H");
|
|
}
|
|
assert_contains!(output, "undefined");
|
|
assert_contains!(output, "const clear = 1234 + 2000;");
|
|
assert_contains!(output, "3234");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_tab_handler() {
|
|
// If the last character is **not** whitespace, we show the completions
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("a\t\t");
|
|
console.write_line("close();");
|
|
let output = console.read_all_output();
|
|
assert_contains!(output, "addEventListener");
|
|
assert_contains!(output, "alert");
|
|
assert_contains!(output, "atob");
|
|
});
|
|
// If the last character is whitespace, we just insert a tab
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("a; \t\t"); // last character is whitespace
|
|
console.write_line("close();");
|
|
let output = console.read_all_output();
|
|
assert_not_contains!(output, "addEventListener");
|
|
assert_not_contains!(output, "alert");
|
|
assert_not_contains!(output, "atob");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repl_report_error() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec![
|
|
r#"console.log(1); reportError(new Error("foo")); console.log(2);"#,
|
|
]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
|
|
// TODO(nayeemrmn): The REPL should report event errors and rejections.
|
|
assert_contains!(out, "1\n2\nundefined\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn pty_aggregate_error() {
|
|
let (out, err) = util::run_and_collect_output(
|
|
true,
|
|
"repl",
|
|
Some(vec!["await Promise.any([])"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
|
|
assert_contains!(out, "AggregateError");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn repl_with_quiet_flag() {
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--quiet"],
|
|
Some(vec!["await Promise.resolve('done')"]),
|
|
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
|
|
false,
|
|
);
|
|
assert!(!out.contains("Deno"));
|
|
assert!(!out.contains("exit using ctrl+d, ctrl+c, or close()"));
|
|
assert_ends_with!(out, "\"done\"\n");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn npm_packages() {
|
|
let mut env_vars = util::env_vars_for_npm_tests();
|
|
env_vars.push(("NO_COLOR".to_owned(), "1".to_owned()));
|
|
let temp_dir = TempDir::new();
|
|
env_vars.push((
|
|
"DENO_DIR".to_string(),
|
|
temp_dir.path().to_string_lossy().to_string(),
|
|
));
|
|
|
|
{
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--quiet", "--allow-read", "--allow-env"],
|
|
Some(vec![
|
|
r#"import chalk from "npm:chalk";"#,
|
|
"chalk.red('hel' + 'lo')",
|
|
]),
|
|
Some(env_vars.clone()),
|
|
true,
|
|
);
|
|
|
|
assert_contains!(out, "hello");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
{
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--quiet", "--allow-read", "--allow-env"],
|
|
Some(vec![
|
|
r#"const chalk = await import("npm:chalk");"#,
|
|
"chalk.default.red('hel' + 'lo')",
|
|
]),
|
|
Some(env_vars.clone()),
|
|
true,
|
|
);
|
|
|
|
assert_contains!(out, "hello");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
{
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--quiet", "--allow-read", "--allow-env"],
|
|
Some(vec![r#"export {} from "npm:chalk";"#]),
|
|
Some(env_vars.clone()),
|
|
true,
|
|
);
|
|
|
|
assert_contains!(out, "Module {");
|
|
assert_contains!(out, "Chalk: [Class: Chalk],");
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
{
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--quiet", "--allow-read", "--allow-env"],
|
|
Some(vec![r#"import foo from "npm:asdfawe52345asdf""#]),
|
|
Some(env_vars.clone()),
|
|
true,
|
|
);
|
|
|
|
assert_contains!(
|
|
out,
|
|
"error: npm package 'asdfawe52345asdf' does not exist"
|
|
);
|
|
assert!(err.is_empty());
|
|
}
|
|
|
|
{
|
|
let (out, err) = util::run_and_collect_output_with_args(
|
|
true,
|
|
vec!["repl", "--quiet", "--allow-read", "--allow-env"],
|
|
Some(vec![
|
|
"import path from 'node:path';",
|
|
"path.isGlob('asdf') ? 'yes' : 'no'",
|
|
]),
|
|
Some(env_vars.clone()),
|
|
true,
|
|
);
|
|
|
|
assert_contains!(out, "no");
|
|
assert!(err.is_empty());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pty_tab_indexable_props() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("const arr = [1, 2, 3]");
|
|
console.write_line("arr.\t\t");
|
|
console.write_line("close();");
|
|
|
|
let output = console.read_all_output();
|
|
println!("output");
|
|
assert_contains!(output, "constructor");
|
|
assert_contains!(output, "sort");
|
|
assert_contains!(output, "at");
|
|
assert_not_contains!(output, "0", "1", "2");
|
|
});
|
|
}
|