mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 23:59:59 -05:00
bac8e4f6f2
This was an oversight because the repl uses the language server under the hood. Also, never preloads from a root directory. Part of #18538
973 lines
24 KiB
Rust
973 lines
24 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;
|
|
use util::TestContext;
|
|
use util::TestContextBuilder;
|
|
|
|
#[test]
|
|
fn pty_multiline() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("(\n1 + 2\n)");
|
|
console.expect("3");
|
|
console.write_line("{\nfoo: \"foo\"\n}");
|
|
console.expect("{ foo: \"foo\" }");
|
|
console.write_line("`\nfoo\n`");
|
|
console.expect("\"\\nfoo\\n\"");
|
|
console.write_line("`\n\\`\n`");
|
|
console.expect(r#""\n`\n""#);
|
|
console.write_line("'{'");
|
|
console.expect(r#""{""#);
|
|
console.write_line("'('");
|
|
console.expect(r#""(""#);
|
|
console.write_line("'['");
|
|
console.expect(r#""[""#);
|
|
console.write_line("/{/");
|
|
console.expect("/{/");
|
|
console.write_line("/\\(/");
|
|
console.expect("/\\(/");
|
|
console.write_line("/\\[/");
|
|
console.expect("/\\[/");
|
|
console.write_line("console.log(\"{test1} abc {test2} def {{test3}}\".match(/{([^{].+?)}/));");
|
|
console.expect("[ \"{test1}\", \"test1\" ]");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_null() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("null");
|
|
console.expect("null");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_unpaired_braces() {
|
|
for right_brace in &[")", "]", "}"] {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line(right_brace);
|
|
console.expect("parse error: Expression expected");
|
|
});
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pty_bad_input() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("'\\u{1f3b5}'[0]");
|
|
console.expect("Unterminated string literal");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_syntax_error_input() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("('\\u')");
|
|
console.expect("Bad character escape sequence, expected 4 hex characters");
|
|
|
|
console.write_line("'");
|
|
console.expect("Unterminated string constant");
|
|
|
|
console.write_line("[{'a'}];");
|
|
console.expect("Expected a semicolon");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_symbol() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line_raw("Symbol.it\t");
|
|
console.expect("Symbol(Symbol.iterator)");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_declarations() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("class MyClass {}");
|
|
console.expect("undefined");
|
|
console.write_line_raw("My\t");
|
|
console.expect("[Class: MyClass]");
|
|
console.write_line("let myVar = 2 + 3;");
|
|
console.expect("undefined");
|
|
console.write_line_raw("myV\t");
|
|
console.expect("5");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_primitives() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("let func = function test(){}");
|
|
console.expect("undefined");
|
|
console.write_line_raw("func.appl\t");
|
|
console.expect("func.apply");
|
|
console.write_line("let str = ''");
|
|
console.expect("undefined");
|
|
console.write_line_raw("str.leng\t");
|
|
console.expect("str.length");
|
|
console.write_line_raw("false.valueO\t");
|
|
console.expect("false.valueOf");
|
|
console.write_line_raw("5n.valueO\t");
|
|
console.expect("5n.valueOf");
|
|
console.write_line("let num = 5");
|
|
console.expect("undefined");
|
|
console.write_line_raw("num.toStrin\t");
|
|
console.expect("num.toString");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_expression() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_raw("Deno.\t\t");
|
|
console.expect("Display all");
|
|
console.write_raw("y");
|
|
console.expect_all(&["symlink", "args", "permissions", "exit"]);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_imports() {
|
|
let context = TestContextBuilder::default().use_temp_cwd().build();
|
|
let temp_dir = context.temp_dir();
|
|
temp_dir.create_dir_all("subdir");
|
|
temp_dir.write("./subdir/my_file.ts", "");
|
|
temp_dir.create_dir_all("run");
|
|
temp_dir.write("./run/hello.ts", "console.log('Hello World');");
|
|
temp_dir.write(
|
|
"./run/output.ts",
|
|
r#"export function output(text: string) {
|
|
console.log(text);
|
|
}
|
|
"#,
|
|
);
|
|
context
|
|
.new_command()
|
|
.args_vec(["repl", "-A"])
|
|
.with_pty(|mut console| {
|
|
// single quotes
|
|
console.write_line_raw("import './run/hel\t'");
|
|
console.expect("Hello World");
|
|
// double quotes
|
|
console.write_line_raw("import { output } from \"./run/out\t\"");
|
|
console.expect("\"./run/output.ts\"");
|
|
console.write_line_raw("output('testing output');");
|
|
console.expect("testing output");
|
|
});
|
|
|
|
// ensure when the directory changes that the suggestions come from the cwd
|
|
context
|
|
.new_command()
|
|
.args_vec(["repl", "-A"])
|
|
.with_pty(|mut console| {
|
|
console.write_line("Deno.chdir('./subdir');");
|
|
console.expect("undefined");
|
|
console.write_line_raw("import '../run/he\t'");
|
|
console.expect("Hello World");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_complete_imports_no_panic_empty_specifier() {
|
|
// does not panic when tabbing when empty
|
|
util::with_pty(&["repl", "-A"], |mut console| {
|
|
if cfg!(windows) {
|
|
console.write_line_raw("import '\t'");
|
|
console.expect_any(&["not prefixed with", "https://deno.land"]);
|
|
} else {
|
|
console.write_raw("import '\t");
|
|
console.expect("import 'https://deno.land");
|
|
}
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_ignore_symbols() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line_raw("Array.Symbol\t");
|
|
console.expect("undefined");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_assign_global_this() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("globalThis = 40 + 2;");
|
|
console.expect("42");
|
|
});
|
|
}
|
|
|
|
#[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.expect("undefined");
|
|
console.write_line("delete globalThis.Deno");
|
|
console.expect("true");
|
|
console.write_line("console.log('testing ' + 'this out');");
|
|
console.expect("testing this out");
|
|
console.expect("undefined");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_internal_repl() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("'Length: ' + Object.keys(globalThis).filter(k => k.startsWith('__DENO_')).length;");
|
|
console.expect("Length: 0");
|
|
|
|
console.write_line_raw("__\t\t");
|
|
console.expect("> __");
|
|
let output = console.read_until("> __");
|
|
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.expect("🦕");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn console_log() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("console.log('hello');");
|
|
console.expect("hello");
|
|
console.write_line("'world'");
|
|
console.expect("\"world\"");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn object_literal() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("{}");
|
|
console.expect("{}");
|
|
console.write_line("{ foo: 'bar' }");
|
|
console.expect("{ foo: \"bar\" }");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn block_expression() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("{};");
|
|
console.expect("undefined");
|
|
console.write_line("{\"\"}");
|
|
console.expect("\"\"");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn await_resolve() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("await Promise.resolve('done')");
|
|
console.expect("\"done\"");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn await_timeout() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("await new Promise((r) => setTimeout(r, 0, 'done'))");
|
|
console.expect("\"done\"");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn let_redeclaration() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("let foo = 0;");
|
|
console.expect("undefined");
|
|
console.write_line("foo");
|
|
console.expect("0");
|
|
console.write_line("let foo = 1;");
|
|
console.expect("undefined");
|
|
console.write_line("foo");
|
|
console.expect("1");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repl_cwd() {
|
|
let context = TestContextBuilder::default().use_temp_cwd().build();
|
|
let temp_dir = context.temp_dir();
|
|
context
|
|
.new_command()
|
|
.args_vec(["repl", "-A"])
|
|
.with_pty(|mut console| {
|
|
console.write_line("Deno.cwd()");
|
|
console.expect(temp_dir.path().file_name().unwrap().to_str().unwrap());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn typescript() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("function add(a: number, b: number) { return a + b }");
|
|
console.expect("undefined");
|
|
console.write_line("const result: number = add(1, 2) as number;");
|
|
console.expect("undefined");
|
|
console.write_line("result");
|
|
console.expect("3");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn typescript_declarations() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("namespace Test { export enum Values { A, B, C } }");
|
|
console.expect("undefined");
|
|
console.write_line("Test.Values.A");
|
|
console.expect("0");
|
|
console.write_line("Test.Values.C");
|
|
console.expect("2");
|
|
console.write_line("interface MyInterface { prop: string; }");
|
|
console.expect("undefined");
|
|
console.write_line("type MyTypeAlias = string;");
|
|
console.expect("undefined");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn typescript_decorators() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console
|
|
.write_line("function dec(target) { target.prototype.test = () => 2; }");
|
|
console.expect("undefined");
|
|
console.write_line("@dec class Test {}");
|
|
console.expect("[Class: Test]");
|
|
console.write_line("new Test().test()");
|
|
console.expect("2");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn eof() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("1 + 2");
|
|
console.expect("3");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn strict() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("let a = {};");
|
|
console.expect("undefined");
|
|
console.write_line("Object.preventExtensions(a)");
|
|
console.expect("{}");
|
|
console.write_line("a.c = 1;");
|
|
console.expect(
|
|
"Uncaught TypeError: Cannot add property c, object is not extensible",
|
|
);
|
|
});
|
|
}
|
|
|
|
#[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() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("Deno.writeFileSync");
|
|
console.expect("[Function: writeFileSync]");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn multiline() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("(\n1 + 2\n)");
|
|
console.expect("3");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn import() {
|
|
let context = TestContextBuilder::default()
|
|
.use_copy_temp_dir("./subdir")
|
|
.build();
|
|
context
|
|
.new_command()
|
|
.args_vec(["repl", "-A"])
|
|
.with_pty(|mut console| {
|
|
console.write_line("import('./subdir/auto_print_hello.ts')");
|
|
console.expect("hello!");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn import_declarations() {
|
|
let context = TestContextBuilder::default()
|
|
.use_copy_temp_dir("./subdir")
|
|
.build();
|
|
context
|
|
.new_command()
|
|
.args_vec(["repl", "-A"])
|
|
.with_pty(|mut console| {
|
|
console.write_line("import './subdir/auto_print_hello.ts'");
|
|
console.expect("hello!");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn exports_stripped() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("const test = 5 + 1; export default test;");
|
|
console.expect("6");
|
|
console.write_line("export class Test {}");
|
|
console.expect("undefined");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn call_eval_unterminated() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("eval('{')");
|
|
console.expect("Unexpected end of input");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn unpaired_braces() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
for right_brace in &[")", "]", "}"] {
|
|
console.write_line(right_brace);
|
|
console.expect("Expression expected");
|
|
}
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn reference_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("not_a_variable");
|
|
console.expect("not_a_variable is not defined");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn syntax_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("syntax error");
|
|
console.expect("parse error: Expected ';', '}' or <eof>");
|
|
// ensure it keeps accepting input after
|
|
console.write_line("7 * 6");
|
|
console.expect("42");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn syntax_error_jsx() {
|
|
// JSX is not supported in the REPL
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("const element = <div />;");
|
|
console.expect("Expression expected");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn type_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("console()");
|
|
console.expect("console is not a function");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn variable() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("var a = 123 + 456;");
|
|
console.expect("undefined");
|
|
console.write_line("a");
|
|
console.expect("579");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn lexical_scoped_variable() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("let a = 123 + 456;");
|
|
console.expect("undefined");
|
|
console.write_line("a");
|
|
console.expect("579");
|
|
});
|
|
}
|
|
|
|
#[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() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("1 + 2");
|
|
console.expect("3");
|
|
console.write_line("_ + 3");
|
|
console.expect("6");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn save_last_thrown() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("throw 1 + 2");
|
|
console.expect("Uncaught 3");
|
|
console.write_line("_error + 3");
|
|
console.expect("6");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn assign_underscore() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("_ = 1");
|
|
console.expect("Last evaluation result is no longer saved to _.");
|
|
console.write_line("2 + 3");
|
|
console.expect("5");
|
|
console.write_line("_");
|
|
console.expect("1");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn assign_underscore_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("_error = 1");
|
|
console.expect("Last thrown error is no longer saved to _error.");
|
|
console.write_line("throw 2");
|
|
console.expect("Uncaught 2");
|
|
console.write_line("_error");
|
|
console.expect("1");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn custom_inspect() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line(
|
|
r#"const o = {
|
|
[Symbol.for("Deno.customInspect")]() {
|
|
throw new Error('Oops custom inspect error');
|
|
},
|
|
};"#,
|
|
);
|
|
console.expect("undefined");
|
|
console.write_line("o");
|
|
console.expect("Oops custom inspect error");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn eval_flag_valid_input() {
|
|
util::with_pty(&["repl", "--eval", "const t = 10;"], |mut console| {
|
|
console.write_line("t * 500");
|
|
console.expect("5000");
|
|
});
|
|
}
|
|
|
|
#[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('h' + 'ello');");
|
|
console.expect_all(&["hello", "undefined"]);
|
|
console.write_line_raw("clear();");
|
|
if cfg!(windows) {
|
|
// expect a bunch of these in the output
|
|
console.expect_raw_in_current_output(
|
|
"\r\n\u{1b}[K\r\n\u{1b}[K\r\n\u{1b}[K\r\n\u{1b}[K\r\n\u{1b}[K",
|
|
);
|
|
} else {
|
|
console.expect_raw_in_current_output("[1;1H");
|
|
}
|
|
console.expect("undefined"); // advance past the "clear()"'s undefined
|
|
console.expect("> ");
|
|
console.write_line("const clear = 1234 + 2000;");
|
|
console.expect("undefined");
|
|
console.write_line("clear;");
|
|
console.expect("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_raw("a\t\t");
|
|
console.expect_all(&["addEventListener", "alert", "atob"]);
|
|
});
|
|
// If the last character is whitespace, we just insert a tab
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("const a = 5;");
|
|
console.expect("undefined");
|
|
console.write_raw("a; \t\ta + 2;\n"); // last character is whitespace
|
|
console.expect_any(&[
|
|
// windows
|
|
"a; a + 2;",
|
|
// unix
|
|
"a; \t\ta + 2;",
|
|
]);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repl_report_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("console.log(1);");
|
|
console.expect_all(&["1", "undefined"]);
|
|
// TODO(nayeemrmn): The REPL should report event errors and rejections.
|
|
console.write_line(r#"reportError(new Error("foo"));"#);
|
|
console.expect("undefined");
|
|
console.write_line("console.log(2);");
|
|
console.expect("2");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pty_aggregate_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("await Promise.any([])");
|
|
console.expect("AggregateError");
|
|
});
|
|
}
|
|
|
|
#[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.expect("undefined");
|
|
console.write_raw("arr.\t\t");
|
|
console.expect("> arr.");
|
|
let output = console.read_until("> arr.");
|
|
assert_contains!(output, "constructor");
|
|
assert_contains!(output, "sort");
|
|
assert_contains!(output, "at");
|
|
assert_not_contains!(output, "0", "1", "2");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn package_json_uncached_no_error() {
|
|
let test_context = TestContextBuilder::for_npm()
|
|
.use_temp_cwd()
|
|
.use_http_server()
|
|
.env("RUST_BACKTRACE", "1")
|
|
.build();
|
|
let temp_dir = test_context.temp_dir();
|
|
temp_dir.write(
|
|
"package.json",
|
|
r#"{
|
|
"dependencies": {
|
|
"@denotest/esm-basic": "1.0.0"
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
test_context.new_command().with_pty(|mut console| {
|
|
console.write_line("console.log(123 + 456);");
|
|
console.expect_all(&["579", "undefined"]);
|
|
assert_not_contains!(
|
|
console.all_output(),
|
|
"Could not set npm package requirements",
|
|
);
|
|
|
|
// should support getting the package now though
|
|
console
|
|
.write_line("import { getValue, setValue } from '@denotest/esm-basic';");
|
|
console.expect_all(&["undefined", "Initialize"]);
|
|
console.write_line("setValue(12 + 30);");
|
|
console.expect("undefined");
|
|
console.write_line("getValue()");
|
|
console.expect("42")
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn closed_file_pre_load_does_not_occur() {
|
|
TestContext::default()
|
|
.new_command()
|
|
.args_vec(["repl", "-A", "--log-level=debug"])
|
|
.with_pty(|console| {
|
|
assert_contains!(
|
|
console.all_output(),
|
|
"Skipping document preload for repl.",
|
|
);
|
|
});
|
|
}
|