mirror of
https://github.com/denoland/deno.git
synced 2024-10-30 09:08:00 -04:00
7f15126f23
This adds a new `PathRef` struct to test_util for making it easier to work with paths in test code. I'm going to expand on this more in the future.
1019 lines
26 KiB
Rust
1019 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;
|
|
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("[");
|
|
console.expect(" \"{test1}\",");
|
|
console.expect(" \"test1\",");
|
|
console.expect(" index: 0,");
|
|
console.expect(" input: \"{test1} abc {test2} def {{test3}}\",");
|
|
console.expect(" groups: undefined");
|
|
console.expect("]");
|
|
});
|
|
}
|
|
|
|
#[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()
|
|
.as_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_string()),
|
|
("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_string()),
|
|
("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_string()),
|
|
("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_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("console.log(1);");
|
|
console.expect_all(&["1", "undefined"]);
|
|
console.write_line(r#"throw new Error("foo");"#);
|
|
console.expect("Uncaught Error: foo");
|
|
console.expect(" at <anonymous>");
|
|
console.write_line("console.log(2);");
|
|
console.expect("2");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repl_reject() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("console.log(1);");
|
|
console.expect_all(&["1", "undefined"]);
|
|
console.write_line(r#"Promise.reject(new Error("foo"));"#);
|
|
console.expect("Promise {");
|
|
console.expect(" <rejected> Error: foo");
|
|
console.expect("Uncaught (in promise) Error: foo");
|
|
console.expect(" at <anonymous>");
|
|
console.write_line("console.log(2);");
|
|
console.expect("2");
|
|
console.write_line(r#"throw "hello";"#);
|
|
console.expect(r#"Uncaught "hello""#);
|
|
console.write_line(r#"throw `hello ${"world"}`;"#);
|
|
console.expect(r#"Uncaught "hello world""#);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repl_report_error() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line("console.log(1);");
|
|
console.expect_all(&["1", "undefined"]);
|
|
console.write_line(r#"reportError(new Error("foo"));"#);
|
|
console.expect("undefined");
|
|
console.expect("Uncaught Error: foo");
|
|
console.expect(" at <anonymous>");
|
|
console.write_line("console.log(2);");
|
|
console.expect("2");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repl_error_undefined() {
|
|
util::with_pty(&["repl"], |mut console| {
|
|
console.write_line(r#"throw undefined;"#);
|
|
console.expect("Uncaught undefined");
|
|
console.write_line(r#"Promise.reject();"#);
|
|
console.expect("Promise { <rejected> undefined }");
|
|
console.expect("Uncaught (in promise) undefined");
|
|
console.write_line(r#"reportError(undefined);"#);
|
|
console.expect("undefined");
|
|
console.expect("Uncaught undefined");
|
|
});
|
|
}
|
|
|
|
#[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()));
|
|
|
|
{
|
|
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: null prototype] {");
|
|
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.",);
|
|
});
|
|
}
|