integration_js_ts.rs
1 mod common; 2 use common::TestFixture; 3 use ecolog_lsp::server::handlers::{ 4 compute_diagnostics, handle_completion, handle_definition, handle_hover, 5 }; 6 use tower_lsp::lsp_types::{ 7 CompletionContext, CompletionParams, CompletionTriggerKind, GotoDefinitionParams, HoverParams, 8 Position, TextDocumentIdentifier, TextDocumentPositionParams, 9 }; 10 11 #[tokio::test] 12 async fn test_js_hover_direct() { 13 let fixture = TestFixture::new().await; 14 let uri = fixture.create_file("test.js", "const a = process.env.DB_URL;"); 15 16 fixture 17 .state 18 .document_manager 19 .open( 20 uri.clone(), 21 "javascript".to_string(), 22 "const a = process.env.DB_URL;".to_string(), 23 0, 24 ) 25 .await; 26 27 let hover = handle_hover( 28 HoverParams { 29 text_document_position_params: TextDocumentPositionParams { 30 text_document: TextDocumentIdentifier { uri }, 31 position: Position::new(0, 22), 32 }, 33 work_done_progress_params: Default::default(), 34 }, 35 &fixture.state, 36 ) 37 .await; 38 39 assert!(hover.is_some()); 40 assert!(format!("{:?}", hover.unwrap()).contains("postgres://")); 41 } 42 43 #[tokio::test] 44 async fn test_js_hover_bracket() { 45 let fixture = TestFixture::new().await; 46 let uri = fixture.create_file("test.js", "const a = process.env['API_KEY'];"); 47 48 fixture 49 .state 50 .document_manager 51 .open( 52 uri.clone(), 53 "javascript".to_string(), 54 "const a = process.env['API_KEY'];".to_string(), 55 0, 56 ) 57 .await; 58 59 let hover = handle_hover( 60 HoverParams { 61 text_document_position_params: TextDocumentPositionParams { 62 text_document: TextDocumentIdentifier { uri }, 63 position: Position::new(0, 25), 64 }, 65 work_done_progress_params: Default::default(), 66 }, 67 &fixture.state, 68 ) 69 .await; 70 71 assert!(hover.is_some()); 72 assert!(format!("{:?}", hover.unwrap()).contains("secret_key")); 73 } 74 75 #[tokio::test] 76 async fn test_js_hover_destructuring() { 77 let fixture = TestFixture::new().await; 78 let uri = fixture.create_file("test.js", "const { PORT } = process.env;"); 79 80 fixture 81 .state 82 .document_manager 83 .open( 84 uri.clone(), 85 "javascript".to_string(), 86 "const { PORT } = process.env;".to_string(), 87 0, 88 ) 89 .await; 90 91 let hover = handle_hover( 92 HoverParams { 93 text_document_position_params: TextDocumentPositionParams { 94 text_document: TextDocumentIdentifier { uri }, 95 position: Position::new(0, 9), 96 }, 97 work_done_progress_params: Default::default(), 98 }, 99 &fixture.state, 100 ) 101 .await; 102 103 assert!(hover.is_some()); 104 assert!(format!("{:?}", hover.unwrap()).contains("8080")); 105 } 106 107 #[tokio::test] 108 async fn test_js_completion_trigger() { 109 let fixture = TestFixture::new().await; 110 let uri = fixture.create_file("test.js", "process.env."); 111 112 fixture 113 .state 114 .document_manager 115 .open( 116 uri.clone(), 117 "javascript".to_string(), 118 "process.env.".to_string(), 119 0, 120 ) 121 .await; 122 123 let completion = handle_completion( 124 CompletionParams { 125 text_document_position: TextDocumentPositionParams { 126 text_document: TextDocumentIdentifier { uri }, 127 position: Position::new(0, 12), 128 }, 129 work_done_progress_params: Default::default(), 130 partial_result_params: Default::default(), 131 context: Some(CompletionContext { 132 trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, 133 trigger_character: Some(".".to_string()), 134 }), 135 }, 136 &fixture.state, 137 ) 138 .await; 139 140 assert!(completion.is_some()); 141 let items = completion.unwrap(); 142 assert!(items.iter().any(|i| i.label == "DB_URL")); 143 assert!(items.iter().any(|i| i.label == "PORT")); 144 } 145 146 #[tokio::test] 147 async fn test_js_definition_direct() { 148 let fixture = TestFixture::new().await; 149 let uri = fixture.create_file("test.js", "process.env.DB_URL"); 150 151 fixture 152 .state 153 .document_manager 154 .open( 155 uri.clone(), 156 "javascript".to_string(), 157 "process.env.DB_URL".to_string(), 158 0, 159 ) 160 .await; 161 162 let def = handle_definition( 163 GotoDefinitionParams { 164 text_document_position_params: TextDocumentPositionParams { 165 text_document: TextDocumentIdentifier { uri }, 166 position: Position::new(0, 15), 167 }, 168 work_done_progress_params: Default::default(), 169 partial_result_params: Default::default(), 170 }, 171 &fixture.state, 172 ) 173 .await; 174 175 assert!(def.is_some()); 176 } 177 178 #[tokio::test] 179 async fn test_js_diagnostics_undefined() { 180 let fixture = TestFixture::new().await; 181 let uri = fixture.create_file("test.js", "process.env.MISSING_VAR"); 182 183 fixture 184 .state 185 .document_manager 186 .open( 187 uri.clone(), 188 "javascript".to_string(), 189 "process.env.MISSING_VAR".to_string(), 190 0, 191 ) 192 .await; 193 194 let diags = compute_diagnostics(&uri, &fixture.state).await; 195 196 assert!(!diags.is_empty()); 197 assert!(diags.iter().any(|d| d.message.contains("not defined"))); 198 } 199 200 #[tokio::test] 201 async fn test_js_object_alias_hover() { 202 let fixture = TestFixture::new().await; 203 204 let content = "const e = process.env; e.PORT;"; 205 let uri = fixture.create_file("test.js", content); 206 207 fixture 208 .state 209 .document_manager 210 .open( 211 uri.clone(), 212 "javascript".to_string(), 213 content.to_string(), 214 0, 215 ) 216 .await; 217 218 let hover = handle_hover( 219 HoverParams { 220 text_document_position_params: TextDocumentPositionParams { 221 text_document: TextDocumentIdentifier { uri }, 222 position: Position::new(0, 26), 223 }, 224 work_done_progress_params: Default::default(), 225 }, 226 &fixture.state, 227 ) 228 .await; 229 230 assert!(hover.is_some()); 231 assert!(format!("{:?}", hover.unwrap()).contains("8080")); 232 } 233 234 #[tokio::test] 235 async fn test_ts_hover_type_cast() { 236 let fixture = TestFixture::new().await; 237 let uri = fixture.create_file("test.ts", "const a = process.env.PORT as string;"); 238 239 fixture 240 .state 241 .document_manager 242 .open( 243 uri.clone(), 244 "typescript".to_string(), 245 "const a = process.env.PORT as string;".to_string(), 246 0, 247 ) 248 .await; 249 250 let hover = handle_hover( 251 HoverParams { 252 text_document_position_params: TextDocumentPositionParams { 253 text_document: TextDocumentIdentifier { uri }, 254 position: Position::new(0, 24), 255 }, 256 work_done_progress_params: Default::default(), 257 }, 258 &fixture.state, 259 ) 260 .await; 261 262 assert!(hover.is_some()); 263 assert!(format!("{:?}", hover.unwrap()).contains("8080")); 264 } 265 266 #[tokio::test] 267 async fn test_ts_completion_on_alias() { 268 let fixture = TestFixture::new().await; 269 let uri = fixture.create_file("test.ts", "const env = process.env; env."); 270 271 fixture 272 .state 273 .document_manager 274 .open( 275 uri.clone(), 276 "typescript".to_string(), 277 "const env = process.env; env.".to_string(), 278 0, 279 ) 280 .await; 281 282 let completion = handle_completion( 283 CompletionParams { 284 text_document_position: TextDocumentPositionParams { 285 text_document: TextDocumentIdentifier { uri }, 286 position: Position::new(0, 29), 287 }, 288 work_done_progress_params: Default::default(), 289 partial_result_params: Default::default(), 290 context: Some(CompletionContext { 291 trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, 292 trigger_character: Some(".".to_string()), 293 }), 294 }, 295 &fixture.state, 296 ) 297 .await; 298 299 if let Some(items) = completion { 300 assert!(items.iter().any(|i| i.label == "PORT")); 301 } else { 302 } 303 } 304 305 #[tokio::test] 306 async fn test_js_hover_destructuring_rename() { 307 let fixture = TestFixture::new().await; 308 let uri = fixture.create_file("test.js", "const { API_KEY: apiKey } = process.env;"); 309 fixture 310 .state 311 .document_manager 312 .open( 313 uri.clone(), 314 "javascript".to_string(), 315 "const { API_KEY: apiKey } = process.env;".to_string(), 316 0, 317 ) 318 .await; 319 320 let hover = handle_hover( 321 HoverParams { 322 text_document_position_params: TextDocumentPositionParams { 323 text_document: TextDocumentIdentifier { uri }, 324 position: Position::new(0, 20), 325 }, 326 work_done_progress_params: Default::default(), 327 }, 328 &fixture.state, 329 ) 330 .await; 331 332 assert!(hover.is_some()); 333 assert!(format!("{:?}", hover.unwrap()).contains("secret_key")); 334 } 335 336 #[tokio::test] 337 async fn test_js_hover_destructuring_property_key() { 338 let fixture = TestFixture::new().await; 339 let uri = fixture.create_file("test.js", "const { API_KEY: apiKey } = process.env;"); 340 fixture 341 .state 342 .document_manager 343 .open( 344 uri.clone(), 345 "javascript".to_string(), 346 "const { API_KEY: apiKey } = process.env;".to_string(), 347 0, 348 ) 349 .await; 350 351 let hover = handle_hover( 352 HoverParams { 353 text_document_position_params: TextDocumentPositionParams { 354 text_document: TextDocumentIdentifier { uri }, 355 position: Position::new(0, 10), 356 }, 357 work_done_progress_params: Default::default(), 358 }, 359 &fixture.state, 360 ) 361 .await; 362 363 assert!(hover.is_some(), "Expected hover on API_KEY property key"); 364 assert!(format!("{:?}", hover.unwrap()).contains("secret_key")); 365 } 366 367 #[tokio::test] 368 async fn test_js_hover_destructuring_rename_bracket() { 369 let fixture = TestFixture::new().await; 370 let uri = fixture.create_file( 371 "test.js", 372 "const { API_KEY: apiKey } = process.env; console.log(apiKey);", 373 ); 374 fixture 375 .state 376 .document_manager 377 .open( 378 uri.clone(), 379 "javascript".to_string(), 380 "const { API_KEY: apiKey } = process.env; console.log(apiKey);".to_string(), 381 0, 382 ) 383 .await; 384 385 let hover = handle_hover( 386 HoverParams { 387 text_document_position_params: TextDocumentPositionParams { 388 text_document: TextDocumentIdentifier { uri }, 389 position: Position::new(0, 55), 390 }, 391 work_done_progress_params: Default::default(), 392 }, 393 &fixture.state, 394 ) 395 .await; 396 397 assert!(hover.is_some()); 398 assert!(format!("{:?}", hover.unwrap()).contains("secret_key")); 399 } 400 401 #[tokio::test] 402 async fn test_js_hover_destructuring_with_default() { 403 let fixture = TestFixture::new().await; 404 let uri = fixture.create_file("test.js", "const { PORT: port = 3000 } = process.env;"); 405 fixture 406 .state 407 .document_manager 408 .open( 409 uri.clone(), 410 "javascript".to_string(), 411 "const { PORT: port = 3000 } = process.env;".to_string(), 412 0, 413 ) 414 .await; 415 416 let hover = handle_hover( 417 HoverParams { 418 text_document_position_params: TextDocumentPositionParams { 419 text_document: TextDocumentIdentifier { uri }, 420 position: Position::new(0, 14), 421 }, 422 work_done_progress_params: Default::default(), 423 }, 424 &fixture.state, 425 ) 426 .await; 427 428 assert!(hover.is_some()); 429 assert!(format!("{:?}", hover.unwrap()).contains("8080")); 430 } 431 432 #[tokio::test] 433 async fn test_js_diagnostics_destructuring_rename_undefined() { 434 let fixture = TestFixture::new().await; 435 let uri = fixture.create_file( 436 "test.js", 437 "const { MISSING_VAR: missing } = process.env; console.log(missing);", 438 ); 439 fixture 440 .state 441 .document_manager 442 .open( 443 uri.clone(), 444 "javascript".to_string(), 445 "const { MISSING_VAR: missing } = process.env; console.log(missing);".to_string(), 446 0, 447 ) 448 .await; 449 450 let diags = compute_diagnostics(&uri, &fixture.state).await; 451 452 assert!(!diags.is_empty()); 453 assert!(diags.iter().any(|d| d.message.contains("not defined"))); 454 } 455 456 #[tokio::test] 457 async fn test_js_diagnostics_destructuring_with_default_undefined() { 458 let fixture = TestFixture::new().await; 459 let uri = fixture.create_file( 460 "test.js", 461 "const { MISSING_VAR: missing = 'default' } = process.env; console.log(missing);", 462 ); 463 fixture 464 .state 465 .document_manager 466 .open( 467 uri.clone(), 468 "javascript".to_string(), 469 "const { MISSING_VAR: missing = 'default' } = process.env; console.log(missing);" 470 .to_string(), 471 0, 472 ) 473 .await; 474 475 let diags = compute_diagnostics(&uri, &fixture.state).await; 476 477 assert!(!diags.is_empty()); 478 assert!(diags.iter().any(|d| d.message.contains("not defined"))); 479 } 480 481 #[tokio::test] 482 async fn test_js_destructuring_multiple() { 483 let fixture = TestFixture::new().await; 484 let uri = fixture.create_file( 485 "test.js", 486 "const { API_KEY: apiKey, PORT: port, DB_URL: dbUrl } = process.env;", 487 ); 488 fixture 489 .state 490 .document_manager 491 .open( 492 uri.clone(), 493 "javascript".to_string(), 494 "const { API_KEY: apiKey, PORT: port, DB_URL: dbUrl } = process.env;".to_string(), 495 0, 496 ) 497 .await; 498 499 let hover = handle_hover( 500 HoverParams { 501 text_document_position_params: TextDocumentPositionParams { 502 text_document: TextDocumentIdentifier { uri: uri.clone() }, 503 position: Position::new(0, 17), 504 }, 505 work_done_progress_params: Default::default(), 506 }, 507 &fixture.state, 508 ) 509 .await; 510 511 assert!(hover.is_some(), "Expected hover on apiKey binding"); 512 assert!(format!("{:?}", hover.unwrap()).contains("secret_key")); 513 514 let hover = handle_hover( 515 HoverParams { 516 text_document_position_params: TextDocumentPositionParams { 517 text_document: TextDocumentIdentifier { uri: uri.clone() }, 518 position: Position::new(0, 31), 519 }, 520 work_done_progress_params: Default::default(), 521 }, 522 &fixture.state, 523 ) 524 .await; 525 526 assert!(hover.is_some(), "Expected hover on port binding"); 527 assert!(format!("{:?}", hover.unwrap()).contains("8080")); 528 529 let hover = handle_hover( 530 HoverParams { 531 text_document_position_params: TextDocumentPositionParams { 532 text_document: TextDocumentIdentifier { uri: uri.clone() }, 533 position: Position::new(0, 45), 534 }, 535 work_done_progress_params: Default::default(), 536 }, 537 &fixture.state, 538 ) 539 .await; 540 541 assert!(hover.is_some(), "Expected hover on dbUrl binding"); 542 assert!(format!("{:?}", hover.unwrap()).contains("postgres://")); 543 } 544 545 #[tokio::test] 546 async fn test_js_destructuring_undefined_and_defined_mix() { 547 let fixture = TestFixture::new().await; 548 let uri = fixture.create_file("test.js", "const { API_KEY: apiKey, MISSING_VAR: missing } = process.env; console.log(apiKey, missing);"); 549 fixture.state.document_manager.open(uri.clone(), "javascript".to_string(), 550 "const { API_KEY: apiKey, MISSING_VAR: missing } = process.env; console.log(apiKey, missing);".to_string(), 0).await; 551 552 let diags = compute_diagnostics(&uri, &fixture.state).await; 553 554 assert!(!diags.is_empty()); 555 assert!(diags.iter().any(|d| d.message.contains("MISSING_VAR"))); 556 } 557 558 #[tokio::test] 559 async fn test_ts_hover_destructuring_rename() { 560 let fixture = TestFixture::new().await; 561 let uri = fixture.create_file("test.ts", "const { API_KEY: apiKey } = process.env;"); 562 fixture 563 .state 564 .document_manager 565 .open( 566 uri.clone(), 567 "typescript".to_string(), 568 "const { API_KEY: apiKey } = process.env;".to_string(), 569 0, 570 ) 571 .await; 572 573 let hover = handle_hover( 574 HoverParams { 575 text_document_position_params: TextDocumentPositionParams { 576 text_document: TextDocumentIdentifier { uri }, 577 position: Position::new(0, 10), 578 }, 579 work_done_progress_params: Default::default(), 580 }, 581 &fixture.state, 582 ) 583 .await; 584 585 assert!(hover.is_some(), "Expected hover on API_KEY property key"); 586 assert!(format!("{:?}", hover.unwrap()).contains("secret_key")); 587 } 588 589 #[tokio::test] 590 async fn test_ts_hover_destructuring_with_default() { 591 let fixture = TestFixture::new().await; 592 let uri = fixture.create_file("test.ts", "const { PORT: port = 3000 } = process.env;"); 593 fixture 594 .state 595 .document_manager 596 .open( 597 uri.clone(), 598 "typescript".to_string(), 599 "const { PORT: port = 3000 } = process.env;".to_string(), 600 0, 601 ) 602 .await; 603 604 let hover = handle_hover( 605 HoverParams { 606 text_document_position_params: TextDocumentPositionParams { 607 text_document: TextDocumentIdentifier { uri }, 608 position: Position::new(0, 14), 609 }, 610 work_done_progress_params: Default::default(), 611 }, 612 &fixture.state, 613 ) 614 .await; 615 616 assert!(hover.is_some()); 617 assert!(format!("{:?}", hover.unwrap()).contains("8080")); 618 } 619 620 #[tokio::test] 621 async fn test_ts_diagnostics_destructuring_rename_undefined() { 622 let fixture = TestFixture::new().await; 623 let uri = fixture.create_file( 624 "test.ts", 625 "const { MISSING_VAR: missing } = process.env; console.log(missing);", 626 ); 627 fixture 628 .state 629 .document_manager 630 .open( 631 uri.clone(), 632 "typescript".to_string(), 633 "const { MISSING_VAR: missing } = process.env; console.log(missing);".to_string(), 634 0, 635 ) 636 .await; 637 638 let diags = compute_diagnostics(&uri, &fixture.state).await; 639 640 assert!(!diags.is_empty()); 641 assert!(diags.iter().any(|d| d.message.contains("not defined"))); 642 } 643 644 #[tokio::test] 645 async fn test_ts_destructuring_with_type_cast_and_rename() { 646 let fixture = TestFixture::new().await; 647 let uri = fixture.create_file( 648 "test.ts", 649 "const { API_KEY: apiKey } = process.env; const typed = apiKey as string;", 650 ); 651 fixture 652 .state 653 .document_manager 654 .open( 655 uri.clone(), 656 "typescript".to_string(), 657 "const { API_KEY: apiKey } = process.env; const typed = apiKey as string;".to_string(), 658 0, 659 ) 660 .await; 661 662 let hover = handle_hover( 663 HoverParams { 664 text_document_position_params: TextDocumentPositionParams { 665 text_document: TextDocumentIdentifier { uri }, 666 position: Position::new(0, 10), 667 }, 668 work_done_progress_params: Default::default(), 669 }, 670 &fixture.state, 671 ) 672 .await; 673 674 assert!(hover.is_some(), "Expected hover on API_KEY property key"); 675 assert!(format!("{:?}", hover.unwrap()).contains("secret_key")); 676 }