diff --git a/.github/workflows/job.test.yml b/.github/workflows/job.test.yml index fb1a507bc..ee96d22d2 100644 --- a/.github/workflows/job.test.yml +++ b/.github/workflows/job.test.yml @@ -26,6 +26,7 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: 1 PYTHONUNBUFFERED: 1 + ATEST_PROCESSES: 2 ATEST_RETRIES: 3 JLPM_CMD: jlpm --ignore-optional --prefer-offline --frozen-lockfile diff --git a/.gitignore b/.gitignore index 995b52c06..87ec95ada 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,7 @@ node_modules *.tgz atest/output/ +.pabotsuitenames junit.xml coverage/ .vscode/ diff --git a/atest/00_Smoke.robot b/atest/00_Smoke.robot index c6ef1a240..5b3aad1a8 100644 --- a/atest/00_Smoke.robot +++ b/atest/00_Smoke.robot @@ -1,6 +1,7 @@ *** Settings *** -Suite Setup Set Screenshot Directory ${SCREENSHOTS DIR}${/}smoke -Resource Keywords.robot +Resource Keywords.resource + +Suite Setup Set Screenshot Directory ${SCREENSHOTS DIR}${/}smoke *** Test Cases *** Lab Version diff --git a/atest/01_Editor.robot b/atest/01_Editor.robot index c3cfd6590..754b4c07c 100644 --- a/atest/01_Editor.robot +++ b/atest/01_Editor.robot @@ -1,33 +1,41 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots editor -Force Tags ui:editor aspect:ls:features -Resource Keywords.robot -Resource Variables.robot +Resource Keywords.resource +Resource Variables.resource + +Suite Setup Setup Suite For Screenshots editor + +Force Tags ui:editor aspect:ls:features *** Test Cases *** Bash - Editor Shows Features for Language Bash example.sh Diagnostics=Failed to parse expression Jump to Definition=fib + Editor Shows Features for Language Bash example.sh Diagnostics=Failed to parse expression + ... Jump to Definition=fib CSS - ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable-2')][contains(text(), '--some-var')])[last()] - Editor Shows Features for Language CSS example.css Diagnostics=Do not use empty rulesets Jump to Definition=${def} Rename=${def} + ${def} = Set Variable + ... xpath:(//span[contains(@class, 'cm-variable-2')][contains(text(), '--some-var')])[last()] + Editor Shows Features for Language CSS example.css Diagnostics=Do not use empty rulesets + ... Jump to Definition=${def} Rename=${def} Docker ${def} = Set Variable xpath://span[contains(@class, 'cm-string')][contains(text(), 'PLANET')] - Wait Until Keyword Succeeds 3x 100ms Editor Shows Features for Language Docker Dockerfile Diagnostics=Instructions should be written in uppercase letters - ... Jump to Definition=${def} Rename=${def} + Wait Until Keyword Succeeds 3x 100ms Editor Shows Features for Language Docker Dockerfile + ... Diagnostics=Instructions should be written in uppercase letters Jump to Definition=${def} + ... Rename=${def} JS ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), 'fib')])[last()] - Editor Shows Features for Language JS example.js Diagnostics=Expression expected Jump to Definition=${def} Rename=${def} + Editor Shows Features for Language JS example.js Diagnostics=Expression expected + ... Jump to Definition=${def} Rename=${def} JSON Editor Shows Features for Language JSON example.json Diagnostics=Duplicate object key JSX ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), 'hello')])[last()] - Editor Shows Features for Language JSX example.jsx Diagnostics=Expression expected Jump to Definition=${def} Rename=${def} -#Julia + Editor Shows Features for Language JSX example.jsx Diagnostics=Expression expected + ... Jump to Definition=${def} Rename=${def} +# Julia # ${def} = Set Variable xpath:(//span[contains(@class, 'cm-builtin')][contains(text(), 'add_together')])[last()] # Editor Shows Features for Language Julia example.jl Jump to Definition=${def} Rename=${def} @@ -38,34 +46,48 @@ LaTeX Less ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable-2')][contains(text(), '@width')])[last()] - Editor Shows Features for Language Less example.less Diagnostics=Do not use empty rulesets Jump to Definition=${def} + Editor Shows Features for Language Less example.less Diagnostics=Do not use empty rulesets + ... Jump to Definition=${def} Markdown Editor Shows Features for Language Markdown example.md Diagnostics=`Color` is misspelt Python (pylsp) ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), 'fib')])[last()] - Editor Shows Features for Server pylsp Python example.py Diagnostics=undefined name 'result' (pyflakes) Jump to Definition=${def} Rename=${def} + Editor Shows Features for Server pylsp Python example.py Diagnostics=undefined name 'result' (pyflakes) + ... Jump to Definition=${def} Rename=${def} Python (pyright) ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), 'fib')])[last()] - Editor Shows Features for Server pyright Python example.py Diagnostics=is not defined (Pyright) Jump to Definition=${def} + Editor Shows Features for Server pyright Python example.py Diagnostics=is not defined (Pyright) + ... Jump to Definition=${def} R ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), 'fib')])[last()] - Editor Shows Features for Language R example.R Diagnostics=Put spaces around all infix operators Jump to Definition=${def} + Editor Shows Features for Language R example.R Diagnostics=Put spaces around all infix operators + ... Jump to Definition=${def} + +Robot Framework + [Tags] gh:332 + ${def} = Set Variable xpath:(//span[contains(@class, 'cm-keyword')][contains(text(), 'Special Log')])[last()] + Editor Shows Features for Language Robot Framework example.robot Diagnostics=Undefined keyword + ... Jump to Definition=${def} SCSS - ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable-2')][contains(text(), 'primary-color')])[last()] - Editor Shows Features for Language SCSS example.scss Diagnostics=Do not use empty rulesets Jump to Definition=${def} + ${def} = Set Variable + ... xpath:(//span[contains(@class, 'cm-variable-2')][contains(text(), 'primary-color')])[last()] + Editor Shows Features for Language SCSS example.scss Diagnostics=Do not use empty rulesets + ... Jump to Definition=${def} TSX ${def} = Set Variable xpath:(//span[contains(@class, 'cm-tag')][contains(text(), 'HelloWorld')])[last()] - Editor Shows Features for Language TSX example.tsx Diagnostics='hello' is declared but its value is never read. Jump to Definition=${def} Rename=${def} + Editor Shows Features for Language TSX example.tsx + ... Diagnostics='hello' is declared but its value is never read. Jump to Definition=${def} Rename=${def} TypeScript ${def} = Set Variable xpath:(//span[contains(@class, 'cm-variable')][contains(text(), 'inc')])[last()] - Editor Shows Features for Language TypeScript example.ts Diagnostics=The left-hand side of an arithmetic Jump to Definition=${def} Rename=${def} + Editor Shows Features for Language TypeScript example.ts Diagnostics=The left-hand side of an arithmetic + ... Jump to Definition=${def} Rename=${def} SQL Editor Shows Features for Language SQL example.sql Diagnostics=Expected @@ -90,9 +112,13 @@ Editor Shows Features for Language Wait Until Fully Initialized # Run Keyword If "${Language}" == "Julia" Sleep 5s FOR ${f} IN @{features} - Run Keyword If "${f}" == "Diagnostics" Editor Should Show Diagnostics ${features["${f}"]} - ... ELSE IF "${f}" == "Jump to Definition" Editor Should Jump To Definition ${features["${f}"]} - ... ELSE IF "${f}" == "Rename" Editor Should Rename ${features["${f}"]} + IF "${f}" == "Diagnostics" + Editor Should Show Diagnostics ${features["${f}"]} + ELSE IF "${f}" == "Jump to Definition" + Editor Should Jump To Definition ${features["${f}"]} + ELSE IF "${f}" == "Rename" + Editor Should Rename ${features["${f}"]} + END END Capture Page Screenshot 99-done.png [Teardown] Clean Up After Working With File ${file} @@ -110,16 +136,17 @@ Editor Should Show Diagnostics Editor Content Changed [Arguments] ${old_content} - ${new_content} Get Editor Content + ${new_content} = Get Editor Content Should Not Be Equal ${old_content} ${new_content} [Return] ${new_content} Editor Should Rename [Arguments] ${symbol} Set Tags feature:rename - ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] + ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} + ... xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] Open Context Menu Over ${sel} - ${old_content} Get Editor Content + ${old_content} = Get Editor Content Capture Page Screenshot 03-rename-0.png Mouse Over ${MENU RENAME} Capture Page Screenshot 03-rename-1.png @@ -128,5 +155,5 @@ Editor Should Rename Input Into Dialog new_name Sleep 2s Capture Page Screenshot 03-rename-3.png - ${new_content} Wait Until Keyword Succeeds 10 x 0.1 s Editor Content Changed ${old_content} + ${new_content} = Wait Until Keyword Succeeds 10 x 0.1 s Editor Content Changed ${old_content} Should Be True "new_name" in """${new_content}""" diff --git a/atest/02_Settings.robot b/atest/02_Settings.robot index 0484c5254..6ae682471 100644 --- a/atest/02_Settings.robot +++ b/atest/02_Settings.robot @@ -1,6 +1,7 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots settings -Resource Keywords.robot +Resource Keywords.resource + +Suite Setup Setup Suite For Screenshots settings *** Test Cases *** Settings diff --git a/atest/03_Notebook.robot b/atest/03_Notebook.robot index 89c39a4d4..2bdfb36ac 100644 --- a/atest/03_Notebook.robot +++ b/atest/03_Notebook.robot @@ -1,7 +1,8 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots notebook -Test Setup Try to Close All Tabs -Resource Keywords.robot +Resource Keywords.resource + +Suite Setup Setup Suite For Screenshots notebook +Test Setup Try to Close All Tabs *** Test Cases *** Python @@ -70,7 +71,8 @@ Code Overrides Wait Until Created ${virtual_path} Wait Until Keyword Succeeds 10x 1s File Should Not Be Empty ${virtual_path} ${document} = Get File ${virtual_path} - Should Be Equal ${document} get_ipython().run_line_magic("ls", "")\n\n\nget_ipython().run_line_magic("pip", " freeze")\n + Should Be Equal ${document} + ... get_ipython().run_line_magic("ls", "")\n\n\nget_ipython().run_line_magic("pip", " freeze")\n [Teardown] Clean Up After Working With File Code overrides.ipynb Adding Text To Cells Is Reflected In Virtual Document diff --git a/atest/04_Interface/BackendFailure.robot b/atest/04_Interface/BackendFailure.robot index aefd8f9f9..0cb5dfa17 100644 --- a/atest/04_Interface/BackendFailure.robot +++ b/atest/04_Interface/BackendFailure.robot @@ -1,11 +1,12 @@ *** Settings *** -Suite Setup Setup Server and Browser server_extension_enabled=${False} -Suite Teardown Setup Server and Browser server_extension_enabled=${True} -Resource ../Keywords.robot +Resource ../Keywords.resource + +Suite Setup Setup Server and Browser server_extension_enabled=${False} +Suite Teardown Setup Server and Browser server_extension_enabled=${True} *** Variables *** -${STATUSBAR} css:div.lsp-statusbar-item -${POPOVER} css:.lsp-popover +${STATUSBAR} css:div.lsp-statusbar-item +${POPOVER} css:.lsp-popover *** Test Cases *** Handles Server Extension Failure diff --git a/atest/04_Interface/DiagnosticsPanel.robot b/atest/04_Interface/DiagnosticsPanel.robot index 721f7775b..b0e89d78f 100644 --- a/atest/04_Interface/DiagnosticsPanel.robot +++ b/atest/04_Interface/DiagnosticsPanel.robot @@ -1,17 +1,19 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots diagnostics_panel -Resource ../Keywords.robot -Force Tags ui:notebook aspect:ls:features -Test Setup Set Up -Test Teardown Clean Up +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots diagnostics_panel +Test Setup Set Up +Test Teardown Clean Up + +Force Tags ui:notebook aspect:ls:features *** Variables *** -${EXPECTED_COUNT} 4 -${DIAGNOSTIC} W291 trailing whitespace (pycodestyle) -${DIAGNOSTIC MESSAGE} trailing whitespace -${DIAGNOSTIC MESSAGE R} Closing curly-braces should always be on their own line -${R CELL} %%R\n{} -${MENU COLUMNS} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "columns")] +${DIAGNOSTIC MESSAGE R} Closing curly-braces should always be on their own line +${DIAGNOSTIC MESSAGE} trailing whitespace +${DIAGNOSTIC} W291 trailing whitespace (pycodestyle) +${EXPECTED_COUNT} 4 +${MENU COLUMNS} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "columns")] +${R CELL} %%R\n{} *** Test Cases *** Diagnostics Panel Opens @@ -45,17 +47,20 @@ Diagnostics Panel Can Be Restored Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_COUNT} Columns Can Be Hidden - Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE} Open Context Menu Over css:.lsp-diagnostics-listing th Capture Page Screenshot 01-menu-visible.png Expand Menu Entry columns Select Menu Entry Message Capture Page Screenshot 03-message-column-toggled.png - Wait Until Keyword Succeeds 10 x 1s Element Should Not Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE} + Wait Until Keyword Succeeds 10 x 1s Element Should Not Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE} Can Sort By Cell # https://github.com/jupyter-lsp/jupyterlab-lsp/issues/707 - Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE} Click Element css:.lsp-diagnostics-listing th[data-id="Line:Ch"] Table Cell Should Equal Line:Ch row=1 column=-1 Table Cell Should Equal 0:0 row=2 column=-1 @@ -68,7 +73,7 @@ Can Sort By Cell Diagnostics Can Be Ignored By Code Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_COUNT} # W291 should be shown twice, lets try to hide it - ${EXPECTED_AFTER} Evaluate ${EXPECTED_COUNT}-2 + ${EXPECTED_AFTER} = Evaluate ${EXPECTED_COUNT}-2 Open Context Menu Over W291 Expand Menu Entry Ignore diagnostics Select Menu Entry code @@ -79,7 +84,7 @@ Diagnostics Can Be Ignored By Code Diagnostics Can Be Ignored By Message Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_COUNT} # W291 should be shown twice, lets try to hide it - ${EXPECTED_AFTER} Evaluate ${EXPECTED_COUNT}-2 + ${EXPECTED_AFTER} = Evaluate ${EXPECTED_COUNT}-2 Open Context Menu Over W291 Expand Menu Entry Ignore diagnostics Capture Page Screenshot 02-menu-visible.png @@ -89,7 +94,8 @@ Diagnostics Can Be Ignored By Message Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_AFTER} Diagnostic Message Can Be Copied - Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE} Open Context Menu Over css:.lsp-diagnostics-listing tbody tr Select Menu Entry Copy diagnostic Close Diagnostics Panel @@ -100,16 +106,20 @@ Diagnostics Panel Works After Removing Foreign Document Lab Command Insert Cell Below Enter Cell Editor 3 Press Keys None ${R CELL} - Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE} - Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE R} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE R} Lab Command Delete Cells # regain focus by entering cell Enter Cell Editor 2 # trigger 7 document updates to trigger the garbage collector that removes unused documents # (search for VirtualDocument.remainining_lifetime for more) Press Keys None 1234567 - Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE} - Wait Until Keyword Succeeds 10 x 1s Element Should Not Contain ${DIAGNOSTICS PANEL} ${DIAGNOSTIC MESSAGE R} + Wait Until Keyword Succeeds 10 x 1s Element Should Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE} + Wait Until Keyword Succeeds 10 x 1s Element Should Not Contain ${DIAGNOSTICS PANEL} + ... ${DIAGNOSTIC MESSAGE R} *** Keywords *** Open Context Menu Over W291 diff --git a/atest/04_Interface/Statusbar.robot b/atest/04_Interface/Statusbar.robot index 9cdcb9600..3b1e6dd0c 100644 --- a/atest/04_Interface/Statusbar.robot +++ b/atest/04_Interface/Statusbar.robot @@ -1,12 +1,13 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots statusbar -Resource ../Keywords.robot +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots statusbar *** Variables *** -${STATUSBAR} css:div.lsp-statusbar-item -${DIAGNOSTIC} W291 trailing whitespace (pycodestyle) -${POPOVER} css:.lsp-popover -${HELP_BUTTON} css:.lsp-popover .lsp-help-button +${STATUSBAR} css:div.lsp-statusbar-item +${DIAGNOSTIC} W291 trailing whitespace (pycodestyle) +${POPOVER} css:.lsp-popover +${HELP_BUTTON} css:.lsp-popover .lsp-help-button *** Test Cases *** Statusbar Popup Opens @@ -21,7 +22,9 @@ Statusbar Popup Opens [Teardown] Clean Up After Working With File Python.ipynb Troubleshooting And Help Is Offered For Known Non-Installed Servers - [Documentation] When specification of a language server has been configured or provided, but the server is not installed (or detected) the user should get help on installation and/or troubleshooting + [Documentation] When specification of a language server has been configured + ... or provided, but the server is not installed (or detected) the user + ... should get help on installation and/or troubleshooting Prepare File for Editing Python status example.klingon Wait Until Element Contains ${STATUSBAR} Initialized (additional servers needed) timeout=60s Click Element ${STATUSBAR} diff --git a/atest/05_Features/Completion.robot b/atest/05_Features/Completion.robot index 93eaec4da..e9ce380a6 100644 --- a/atest/05_Features/Completion.robot +++ b/atest/05_Features/Completion.robot @@ -1,19 +1,22 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots completion -Test Setup Setup Completion Test -Test Teardown Clean Up After Working With File Completion.ipynb -Force Tags feature:completion -Resource ../Keywords.robot +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots completion +Test Setup Setup Completion Test +Test Teardown Clean Up After Working With File Completion.ipynb + +Force Tags feature:completion *** Variables *** -${COMPLETER_BOX} css:.jp-Completer.jp-HoverBox -${DOCUMENTATION_PANEL} css:.jp-Completer-docpanel +${COMPLETER_BOX} css:.jp-Completer.jp-HoverBox +${DOCUMENTATION_PANEL} css:.jp-Completer-docpanel ${KERNEL_BUSY_INDICATOR} css:.jp-NotebookPanel-toolbar div[title="Kernel Busy"] *** Test Cases *** Works When Kernel Is Idle - Configure JupyterLab Plugin {"kernelResponseTimeout": -1, "waitForBusyKernel": false, "caseSensitive": false} plugin id=${COMPLETION PLUGIN ID} [Documentation] The suggestions from kernel and LSP should get integrated; operates in case insensitive mode + Configure JupyterLab Plugin {"kernelResponseTimeout": -1, "waitForBusyKernel": false, "caseSensitive": false} + ... plugin id=${COMPLETION PLUGIN ID} Enter Cell Editor 1 line=2 Capture Page Screenshot 01-entered-cell.png Trigger Completer @@ -29,8 +32,8 @@ Works When Kernel Is Idle Should Contain ${content} TabError Filters Completions In Case Sensitive Mode - Configure JupyterLab Plugin {"caseSensitive": true} plugin id=${COMPLETION PLUGIN ID} [Documentation] Completions filtering is case-sensitive when caseSensitive is true + Configure JupyterLab Plugin {"caseSensitive": true} plugin id=${COMPLETION PLUGIN ID} Enter Cell Editor 1 line=2 Trigger Completer Completer Should Suggest test @@ -38,7 +41,9 @@ Filters Completions In Case Sensitive Mode Can Prioritize Kernel Completions # note: disabling pre-filtering to get ranking without match scoring - Configure JupyterLab Plugin {"kernelCompletionsFirst": true, "kernelResponseTimeout": -1, "preFilterMatches": false} plugin id=${COMPLETION PLUGIN ID} + Configure JupyterLab Plugin + ... {"kernelCompletionsFirst": true, "kernelResponseTimeout": -1, "preFilterMatches": false} + ... plugin id=${COMPLETION PLUGIN ID} Enter Cell Editor 1 line=2 Trigger Completer Completer Should Suggest %%timeit @@ -48,7 +53,9 @@ Can Prioritize Kernel Completions Can Prioritize LSP Completions # note: disabling pre-filtering to get ranking without match scoring - Configure JupyterLab Plugin {"kernelCompletionsFirst": false, "kernelResponseTimeout": -1, "preFilterMatches": false} plugin id=${COMPLETION PLUGIN ID} + Configure JupyterLab Plugin + ... {"kernelCompletionsFirst": false, "kernelResponseTimeout": -1, "preFilterMatches": false} + ... plugin id=${COMPLETION PLUGIN ID} Enter Cell Editor 1 line=2 Trigger Completer Completer Should Suggest %%timeit @@ -76,12 +83,14 @@ Invalidates On Focus Loss Enter Cell Editor 1 line=2 Uses LSP Completions When Kernel Resoponse Times Out - Configure JupyterLab Plugin {"kernelResponseTimeout": 1, "waitForBusyKernel": true} plugin id=${COMPLETION PLUGIN ID} + Configure JupyterLab Plugin {"kernelResponseTimeout": 1, "waitForBusyKernel": true} + ... plugin id=${COMPLETION PLUGIN ID} Should Complete While Kernel Is Busy Uses LSP Completions When Kernel Is Busy [Documentation] When kernel is not available the best thing is to show some suggestions (LSP) rather than none. - Configure JupyterLab Plugin {"kernelResponseTimeout": -1, "waitForBusyKernel": false} plugin id=${COMPLETION PLUGIN ID} + Configure JupyterLab Plugin {"kernelResponseTimeout": -1, "waitForBusyKernel": false} + ... plugin id=${COMPLETION PLUGIN ID} Should Complete While Kernel Is Busy Works When Kernel Is Shut Down @@ -205,7 +214,8 @@ Completion Works For Tokens Separated By Space Kernel And LSP Completions Merge Prefix Conflicts Are Resolved [Documentation] Reconciliate Python kernel returning prefixed completions and LSP (pylsp) not-prefixed ones - Configure JupyterLab Plugin {"kernelResponseTimeout": -1, "waitForBusyKernel": false} plugin id=${COMPLETION PLUGIN ID} + Configure JupyterLab Plugin {"kernelResponseTimeout": -1, "waitForBusyKernel": false} + ... plugin id=${COMPLETION PLUGIN ID} # For more details see: https://github.com/jupyter-lsp/jupyterlab-lsp/issues/30#issuecomment-576003987 # `import os.pat` → `import os.pathsep` Enter Cell Editor 15 line=1 @@ -268,7 +278,8 @@ Works Without A Theme Wait Until Page Contains Element ${COMPLETER_BOX} .jp-Completer-monogram Works With Incorrect Theme - Configure JupyterLab Plugin {"theme": "a-non-existing-theme", "caseSensitive": false} plugin id=${COMPLETION PLUGIN ID} + Configure JupyterLab Plugin {"theme": "a-non-existing-theme", "caseSensitive": false} + ... plugin id=${COMPLETION PLUGIN ID} Capture Page Screenshot 01-configured.png Enter Cell Editor 1 line=2 Trigger Completer @@ -350,11 +361,13 @@ Setup Completion Test Get Cell Editor Content [Arguments] ${cell_nr} - ${content} Execute JavaScript return document.querySelector('.jp-Cell:nth-child(${cell_nr}) .CodeMirror').CodeMirror.getValue() + ${content} = Execute JavaScript + ... return document.querySelector('.jp-Cell:nth-child(${cell_nr}) .CodeMirror').CodeMirror.getValue() [Return] ${content} Get File Editor Content - ${content} Execute JavaScript return document.querySelector('.jp-FileEditorCodeWrapper .CodeMirror').CodeMirror.getValue() + ${content} = Execute JavaScript + ... return document.querySelector('.jp-FileEditorCodeWrapper .CodeMirror').CodeMirror.getValue() [Return] ${content} Cell Editor Should Equal diff --git a/atest/05_Features/Diagnostics.robot b/atest/05_Features/Diagnostics.robot index f13e536a1..c5f5627cd 100644 --- a/atest/05_Features/Diagnostics.robot +++ b/atest/05_Features/Diagnostics.robot @@ -1,9 +1,11 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots diagnostics -Force Tags feature:diagnostics -Test Setup Setup Notebook Python Diagnostic.ipynb -Test Teardown Clean Up After Working With File Diagnostic.ipynb -Resource ../Keywords.robot +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots diagnostics +Test Setup Setup Notebook Python Diagnostic.ipynb +Test Teardown Clean Up After Working With File Diagnostic.ipynb + +Force Tags feature:diagnostics # note: diagnostics are also tested in 01_Editor and 04_Interface/DiagnosticsPanel.robot *** Test Cases *** diff --git a/atest/05_Features/Highlights.robot b/atest/05_Features/Highlights.robot index 657e75046..ca124b602 100644 --- a/atest/05_Features/Highlights.robot +++ b/atest/05_Features/Highlights.robot @@ -1,9 +1,11 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots highlights -Test Setup Setup Highlights Test -Test Teardown Clean Up After Working With File Highlights.ipynb -Force Tags feature:highlights -Resource ../Keywords.robot +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots highlights +Test Setup Setup Highlights Test +Test Teardown Clean Up After Working With File Highlights.ipynb + +Force Tags feature:highlights *** Test Cases *** # cursor is symbolized by pipe (|), for example when @@ -64,12 +66,14 @@ Should Not Highlight Any Tokens Should Highlight Token [Arguments] ${token} ${timeout}=15s - ${token_element} Set Variable xpath://span[contains(@class, 'cm-lsp-highlight')][contains(text(), '${token}')] + ${token_element} Set Variable + ... xpath://span[contains(@class, 'cm-lsp-highlight')][contains(text(), '${token}')] Wait Until Page Contains Element ${token_element} timeout=${timeout} Should Not Highlight Token [Arguments] ${token} ${timeout}=15s - ${token_element} Set Variable xpath://span[contains(@class, 'cm-lsp-highlight')][contains(text(), '${token}')] + ${token_element} Set Variable + ... xpath://span[contains(@class, 'cm-lsp-highlight')][contains(text(), '${token}')] Wait Until Page Does Not Contain Element ${token_element} timeout=${timeout} Setup Highlights Test diff --git a/atest/05_Features/Hover.robot b/atest/05_Features/Hover.robot index e5610e6a7..0ddc09d17 100644 --- a/atest/05_Features/Hover.robot +++ b/atest/05_Features/Hover.robot @@ -1,14 +1,16 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots hover -Test Setup Setup Hover Test -Test Teardown Clean Up After Working With File Hover.ipynb -Force Tags feature:hover -Resource ../Keywords.robot -Library ../mouse_over_extension.py +Resource ../Keywords.resource +Library ../mouse_over_extension.py + +Suite Setup Setup Suite For Screenshots hover +Test Setup Setup Hover Test +Test Teardown Clean Up After Working With File Hover.ipynb + +Force Tags feature:hover *** Variables *** -${HOVER_BOX} css:.lsp-hover -${HOVER_SIGNAL} css:.cm-lsp-hover-available +${HOVER_BOX} css:.lsp-hover +${HOVER_SIGNAL} css:.cm-lsp-hover-available *** Test Cases *** Hover works in notebooks @@ -47,7 +49,8 @@ Hover works in foreign code (javascript) *** Keywords *** Last Occurrence [Arguments] ${symbol} - ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] + ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} + ... xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] [Return] ${sel} Trigger Via Hover With Modifier @@ -70,8 +73,8 @@ Trigger Via Modifier Key Press Wait Until Keyword Succeeds 4x 0.1s Page Should Contain Element ${HOVER_BOX} Trigger Tooltip - [Arguments] ${symbol} [Documentation] The default way to trigger the hover tooltip + [Arguments] ${symbol} ${sel} = Last Occurrence ${symbol} Wait Until Keyword Succeeds 4x 0.1 s Trigger Via Hover With Modifier ${sel} @@ -81,4 +84,6 @@ Setup Hover Test Wokraround Visibility Problem [Arguments] ${sel} ${width} ${height} = Get Element Size ${sel} - Run Keyword If ${width} == 0 Cover Element ${sel} # don't know why but otherwise it raises Message: TypeError: rect is undefined + IF ${width} == 0 + Cover Element ${sel} + END diff --git a/atest/05_Features/Jump.robot b/atest/05_Features/Jump.robot index 8de249436..1b3ba03d3 100644 --- a/atest/05_Features/Jump.robot +++ b/atest/05_Features/Jump.robot @@ -1,7 +1,9 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots gh-403 -Force Tags feature:jump-to-definition gh:403 -Resource ../Keywords.robot +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots gh-403 + +Force Tags feature:jump-to-definition gh:403 *** Variables *** ${FOLDER WITH SPACE} a föl@der @@ -11,7 +13,7 @@ Python Jumps Between Files Copy Files to Folder With Spaces jump_a.py jump_b.py Open ${FOLDER WITH SPACE}/jump_b.py in ${MENU EDITOR} Wait Until Fully Initialized - ${sel} = Select Token Occurrence a_function_definition + ${sel} = Select Token Occurrence a_function_definition Jump To Definition ${sel} Wait Until Page Contains ANOTHER_CONSTANT Capture Page Screenshot 10-jumped.png @@ -21,14 +23,14 @@ Jumps To References With Modifier Click [Setup] Prepare File for Editing Python editor jump_references.py Configure JupyterLab Plugin {"modifierKey": "Accel"} plugin id=${JUMP PLUGIN ID} Wait Until Fully Initialized - ${token} = Select Token Occurrence func type=def + ${token} = Select Token Occurrence func type=def Click Element ${token} ${original} = Measure Cursor Position - Ctrl Click Element ${token} - Wait Until Page Contains Choose the jump target - ${references_count} = Get Element Count css:.jp-Dialog select option + Ctrl Click Element ${token} + Wait Until Page Contains Choose the jump target + ${references_count} = Get Element Count css:.jp-Dialog select option Should Be True ${references_count} == ${3} - Select From List By Index css:.jp-Dialog select 2 + Select From List By Index css:.jp-Dialog select 2 Click Element css:.jp-Dialog-button.jp-mod-accept Wait Until Keyword Succeeds 10 x 1 s Cursor Should Jump ${original} Clean Up After Working With File jump_references.py @@ -36,15 +38,15 @@ Jumps To References With Modifier Click Jumps To References From Context Menu [Setup] Prepare File for Editing Python editor jump_references.py Wait Until Fully Initialized - ${token} = Select Token Occurrence func type=def + ${token} = Select Token Occurrence func type=def Click Element ${token} ${original} = Measure Cursor Position - Open Context Menu Over ${token} + Open Context Menu Over ${token} Select Menu Entry Jump to references - Wait Until Page Contains Choose the jump target - ${references_count} = Get Element Count css:.jp-Dialog select option + Wait Until Page Contains Choose the jump target + ${references_count} = Get Element Count css:.jp-Dialog select option Should Be True ${references_count} == ${3} - Select From List By Index css:.jp-Dialog select 2 + Select From List By Index css:.jp-Dialog select 2 Click Element css:.jp-Dialog-button.jp-mod-accept Wait Until Keyword Succeeds 10 x 1 s Cursor Should Jump ${original} Clean Up After Working With File jump_references.py @@ -57,7 +59,7 @@ Ctrl Click And Jumping Back Works Click Element ${sel} ${original} = Measure Cursor Position Capture Page Screenshot 01-ready-to-jump.png - Ctrl Click Element ${sel} + Ctrl Click Element ${sel} Capture Page Screenshot 02-jumped.png Wait Until Keyword Succeeds 10 x 1 s Cursor Should Jump ${original} ${new} = Measure Cursor Position @@ -79,10 +81,12 @@ Copy Files to Folder With Spaces Select Token Occurrence [Arguments] ${token} ${type}=variable ${which}=last - [Return] xpath:(//span[contains(@class, 'cm-${type}')][contains(text(), '${token}')])[${which}()] + ${sel} = Set Variable + ... xpath:(//span[contains(@class, 'cm-${type}')][contains(text(), '${token}')])[${which}()] + [Return] ${sel} Ctrl Click Element - [Arguments] ${element} + [Arguments] ${element} ${key} = Evaluate 'COMMAND' if platform.system() == 'Darwin' else 'CTRL' platform Click Element ${element} modifier=${key} diff --git a/atest/05_Features/Signature.robot b/atest/05_Features/Signature.robot index 2dd717f29..1a5c5d279 100644 --- a/atest/05_Features/Signature.robot +++ b/atest/05_Features/Signature.robot @@ -1,16 +1,18 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots signature -Force Tags feature:signature -Resource ../Keywords.robot -Test Setup Setup Notebook Python Signature.ipynb -Test Teardown Clean Up After Working With File Signature.ipynb +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots signature +Test Setup Setup Notebook Python Signature.ipynb +Test Teardown Clean Up After Working With File Signature.ipynb + +Force Tags feature:signature *** Variables *** -${SIGNATURE PLUGIN ID} @krassowski/jupyterlab-lsp:signature -${SIGNATURE_BOX} css:.lsp-signature-help +${SIGNATURE PLUGIN ID} @krassowski/jupyterlab-lsp:signature +${SIGNATURE_BOX} css:.lsp-signature-help ${SIGNATURE_HIGHLIGHTED_ARG} css:.lsp-signature-help mark -${SIGNATURE_DETAILS_CSS} .lsp-signature-help details -${SIGNATURE_DETAILS} css:${SIGNATURE_DETAILS_CSS} +${SIGNATURE_DETAILS_CSS} .lsp-signature-help details +${SIGNATURE_DETAILS} css:${SIGNATURE_DETAILS_CSS} *** Test Cases *** Triggers Signature Help After A Keystroke @@ -19,12 +21,14 @@ Triggers Signature Help After A Keystroke Press Keys None ( Capture Page Screenshot 02-signature-shown.png Wait Until Keyword Succeeds 20x 0.5s Page Should Contain Element ${SIGNATURE_BOX} - Wait Until Keyword Succeeds 10x 0.5s Element Should Contain ${SIGNATURE_BOX} Important docstring of abc() + Wait Until Keyword Succeeds 10x 0.5s Element Should Contain ${SIGNATURE_BOX} + ... Important docstring of abc() Element Should Contain ${SIGNATURE_HIGHLIGHTED_ARG} x # should remain visible after typing an argument Press Keys None x=2, Wait For Ready State - Wait Until Keyword Succeeds 10x 0.5s Element Should Contain ${SIGNATURE_BOX} Important docstring of abc() + Wait Until Keyword Succeeds 10x 0.5s Element Should Contain ${SIGNATURE_BOX} + ... Important docstring of abc() # and should switch highlight to y Wait Until Keyword Succeeds 20x 0.5s Element Should Contain ${SIGNATURE_HIGHLIGHTED_ARG} y Press Keys None LEFT diff --git a/atest/05_Features/Syntax_highlighting.robot b/atest/05_Features/Syntax_highlighting.robot index 04e1b921b..aa6581a7f 100644 --- a/atest/05_Features/Syntax_highlighting.robot +++ b/atest/05_Features/Syntax_highlighting.robot @@ -1,9 +1,11 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots syntax_highlighting -Test Setup Setup Highlighting Test -Test Teardown Clean Up After Working With File Syntax highlighting.ipynb -Force Tags feature:syntax_highlighting -Resource ../Keywords.robot +Resource ../Keywords.resource + +Suite Setup Setup Suite For Screenshots syntax_highlighting +Test Setup Setup Highlighting Test +Test Teardown Clean Up After Working With File Syntax highlighting.ipynb + +Force Tags feature:syntax_highlighting *** Test Cases *** Syntax Highlighting Mode Stays Normal In Normal Cells @@ -40,7 +42,8 @@ Get Mode Of A Cell [Arguments] ${cell_number} Click Element css:.jp-Cell:nth-child(${cell_number}) Wait Until Page Contains Element css:.jp-Cell:nth-child(${cell_number}) .CodeMirror-focused - ${mode} = Execute JavaScript return document.querySelector('.jp-Cell:nth-child(${cell_number}) .CodeMirror').CodeMirror.getMode() + ${mode} = Execute JavaScript + ... return document.querySelector('.jp-Cell:nth-child(${cell_number}) .CodeMirror').CodeMirror.getMode() [Return] ${mode} Setup Highlighting Test diff --git a/atest/06_Style.robot b/atest/06_Style.robot index 0866745b0..f1cd52e03 100644 --- a/atest/06_Style.robot +++ b/atest/06_Style.robot @@ -1,12 +1,14 @@ *** Settings *** -Suite Setup Setup Suite For Screenshots style -Force Tags ui:editor aspect:style -Resource Keywords.robot -Resource Variables.robot -Library Collections +Resource Keywords.resource +Resource Variables.resource +Library Collections + +Suite Setup Setup Suite For Screenshots style + +Force Tags ui:editor aspect:style *** Variables *** -${THEME NAMES} ${EMPTY} +${THEME NAMES} ${EMPTY} *** Test Cases *** Light @@ -22,7 +24,9 @@ Screenshot Editor Themes with Lab Theme Set Tags theme:lab:${norm lab theme} Set Screenshot Directory ${SCREENSHOTS DIR}${/}style${/}${norm lab theme} Copy File examples${/}${file} ${NOTEBOOK DIR}${/}${file} - Run Keyword If "${THEME NAMES}" == "" Wait Until Keyword Succeeds 3x 1s Get Theme Names + IF "${THEME NAMES}" == "" + Wait Until Keyword Succeeds 3x 1s Get Theme Names + END Lab Command Use Theme: ${lab theme} Try to Close All Tabs Setup Notebook python ${notebook} isolated=${False} @@ -48,7 +52,8 @@ Capture Theme Screenshot Capture Page Screenshot 01-editor-${editor theme.replace(' ', '-')}.png Click the second Accumulate in ${editor} - Click Element //div[contains(@class, 'jp-${editor}')]//div[contains(@class,'CodeMirror')]//span[text() = 'accumulate'] + Click Element + ... //div[contains(@class, 'jp-${editor}')]//div[contains(@class,'CodeMirror')]//span[text() = 'accumulate'] Change Editor Theme [Arguments] ${editor theme} diff --git a/atest/07_Configuration.robot b/atest/07_Configuration.robot index 070a63e2a..0feabd4b0 100644 --- a/atest/07_Configuration.robot +++ b/atest/07_Configuration.robot @@ -1,8 +1,11 @@ *** Settings *** -Documentation Configuration of language servers -Suite Setup Setup Suite For Screenshots config -Force Tags feature:config -Resource ./Keywords.robot +Documentation Configuration of language servers + +Resource ./Keywords.resource + +Suite Setup Setup Suite For Screenshots config + +Force Tags feature:config *** Test Cases *** Python @@ -23,8 +26,7 @@ Markdown [Documentation] different englishes spell colou?r differently Settings Should Change Editor Diagnostics Markdown example.md unified-language-server ... {"unified-language-server":{"remark-parse":{"plugins":[["#remark-retext","#parse-latin"],["#retext-spell","#dictionary-en"]]}}} - ... `Color` is misspelt - ... `Colour` is misspelt + ... `Color` is misspelt `Colour` is misspelt LaTeX [Documentation] diagnostics only appear if configured @@ -52,7 +54,9 @@ Settings Should Change Editor Diagnostics Open Diagnostics Panel Drag and Drop By Offset ${JLAB XP DOCK TAB}\[contains(., 'Diagnostics Panel')] 600 -200 Click Element ${JLAB XP DOCK TAB}\[contains(., 'Launcher')]/${close icon} - Run Keyword If "${before}" Wait Until Page Contains Element ${before diagnostic} timeout=30s + IF "${before}" + Wait Until Page Contains Element ${before diagnostic} timeout=30s + END Page Should Not Contain ${after diagnostic} Capture Page Screenshot 01-default-diagnostics-and-settings.png Set Editor Content {"language_servers": {"${server}": {"serverSettings": ${settings}}}} ${CSS USER SETTINGS} @@ -64,7 +68,9 @@ Settings Should Change Editor Diagnostics Lab Command ${save command} Ensure Sidebar Is Closed Capture Page Screenshot 03-settings-changed.png - Run Keyword If ${needs reload} Reload After Configuration ${language} ${file} + IF ${needs reload} + Reload After Configuration ${language} ${file} + END Wait Until Page Contains Element ${after diagnostic} timeout=30s Capture Page Screenshot 04-configured-diagnostic-found.png [Teardown] Clean Up After Working with File and Settings ${file} diff --git a/atest/Keywords.robot b/atest/Keywords.resource similarity index 87% rename from atest/Keywords.robot rename to atest/Keywords.resource index a89466b99..a68c2da2a 100644 --- a/atest/Keywords.robot +++ b/atest/Keywords.resource @@ -1,13 +1,13 @@ *** Settings *** -Resource Variables.robot -Library SeleniumLibrary -Library OperatingSystem -Library Process -Library String -Library Collections -Library ./logcheck.py -Library ./ports.py -Library ./config.py +Library OperatingSystem +Library Process +Library String +Library Collections +Library SeleniumLibrary +Resource Variables.resource +Library ./logcheck.py +Library ./ports.py +Library ./config.py *** Keywords *** Setup Server and Browser @@ -37,8 +37,8 @@ Initialize Global Variables Set Screenshot Directory ${SCREENSHOTS DIR} Create Notebok Server Config - [Arguments] ${server_extension_enabled}=${True} [Documentation] Copies in notebook server config file and updates accordingly + [Arguments] ${server_extension_enabled}=${True} ${conf} = Set Variable ${NOTEBOOK DIR}${/}${NBSERVER CONF} ${extra_node_roots} = Create List ${ROOT} ${port} = Get Unused Port @@ -112,23 +112,16 @@ Wait For Splash Open JupyterLab Set Environment Variable MOZ_HEADLESS ${HEADLESS} - ${firefox} = Get Firefox Binary ${geckodriver} = Which geckodriver - Should Not Be Equal As Strings ${geckodriver} None geckodriver not found, do you need to install firefox-geckodriver? + Should Not Be Equal As Strings ${geckodriver} None + ... geckodriver not found, do you need to install firefox-geckodriver? ${service args} = Create List --log debug Create WebDriver Firefox ... executable_path=${geckodriver} - ... firefox_binary=${firefox} ... service_log_path=${GECKODRIVER LOG} ... service_args=${service args} Wait Until Keyword Succeeds 3x 5s Wait For Splash -Get Firefox Binary - [Documentation] Get Firefox path from the environment... or hope for the best - ${from which} = Which firefox - ${firefox} = Set Variable If "%{FIREFOX_BINARY}" %{FIREFOX_BINARY} ${from which} - [Return] ${firefox} - Close JupyterLab Close All Browsers @@ -150,15 +143,23 @@ Reset Application State Accept Default Dialog Option [Documentation] Accept a dialog, if it exists ${el} = Get WebElements ${CSS DIALOG OK} - Run Keyword If ${el.__len__()} Click Element ${CSS DIALOG OK} + IF ${el.__len__()} + Click Element ${CSS DIALOG OK} + END Ensure All Kernels Are Shut Down Enter Command Name Shut Down All Kernels ${els} = Get WebElements ${CMD PALETTE ITEM ACTIVE} - Run Keyword If ${els.__len__()} Click Element ${CMD PALETTE ITEM ACTIVE} + IF ${els.__len__()} + Click Element ${CMD PALETTE ITEM ACTIVE} + END ${accept} = Set Variable css:.jp-mod-accept.jp-mod-warn - Run Keyword If ${els.__len__()} Wait Until Page Contains Element ${accept} - Run Keyword If ${els.__len__()} Click Element ${accept} + IF ${els.__len__()} + Wait Until Page Contains Element ${accept} + END + IF ${els.__len__()} + Click Element ${accept} + END Open Command Palette Press Keys id:main ${ACCEL}+SHIFT+c @@ -182,25 +183,25 @@ Which [Return] ${path} Click JupyterLab Menu - [Arguments] ${label} [Documentation] Click a top-level JupyterLab menu bar item with by ``label``, ... e.g. File, Help, etc. + [Arguments] ${label} ${xpath} = Set Variable xpath:${JLAB XP TOP}${JLAB XP MENU LABEL}\[text() = '${label}'] Wait Until Page Contains Element ${xpath} Mouse Over ${xpath} Click Element ${xpath} Click JupyterLab Menu Item - [Arguments] ${label} [Documentation] Click a currently-visible JupyterLab menu item by ``label``. + [Arguments] ${label} ${item} = Set Variable ${JLAB XP MENU ITEM LABEL}\[text() = '${label}'] Wait Until Page Contains Element ${item} Mouse Over ${item} Click Element ${item} Open With JupyterLab Menu - [Arguments] ${menu} @{submenus} [Documentation] Click into a ``menu``, then a series of ``submenus`` + [Arguments] ${menu} @{submenus} Click JupyterLab Menu ${menu} FOR ${submenu} IN @{submenus} Click JupyterLab Menu Item ${submenu} @@ -209,12 +210,16 @@ Open With JupyterLab Menu Ensure File Browser is Open ${sel} = Set Variable css:.lm-TabBar-tab[data-id="filebrowser"]:not(.lm-mod-current) ${els} = Get WebElements ${sel} - Run Keyword If ${els.__len__()} Click Element ${sel} + IF ${els.__len__()} + Click Element ${sel} + END Ensure Sidebar Is Closed [Arguments] ${side}=left ${els} = Get WebElements css:#jp-${side}-stack - Run Keyword If ${els.__len__()} Click Element css:.jp-mod-${side} .lm-TabBar-tab.lm-mod-current + IF ${els.__len__()} + Click Element css:.jp-mod-${side} .lm-TabBar-tab.lm-mod-current + END Open Context Menu for File [Arguments] ${file} @@ -252,7 +257,9 @@ Open Folder Open ${file} in ${editor} ${paths} = Set Variable ${file.split("/")} - Run Keyword If ${paths.__len__() > 1} Open Folder @{paths[:-1]} + IF ${paths.__len__() > 1} + Open Folder @{paths[:-1]} + END ${file} = Set Variable ${paths[-1]} Open Context Menu for File ${file} Mouse Over ${MENU OPEN WITH} @@ -269,14 +276,18 @@ Clean Up After Working With File Setup Notebook [Arguments] ${Language} ${file} ${isolated}=${True} ${wait}=${True} Set Tags language:${Language.lower()} - Run Keyword If ${isolated} Set Screenshot Directory ${SCREENSHOTS DIR}${/}notebook${/}${TEST NAME.replace(' ', '_')} + IF ${isolated} + Set Screenshot Directory ${SCREENSHOTS DIR}${/}notebook${/}${TEST NAME.replace(' ', '_')} + END Copy File examples${/}${file} ${NOTEBOOK DIR}${/}${file} - Run Keyword If ${isolated} Try to Close All Tabs + IF ${isolated} + Try to Close All Tabs + END Open ${file} in ${MENU NOTEBOOK} Capture Page Screenshot 00-notebook-opened.png - Run Keyword If - ... ${wait} - ... Wait Until Fully Initialized + IF ${wait} + Wait Until Fully Initialized + END Capture Page Screenshot 01-notebook-initialized.png Open Diagnostics Panel @@ -310,7 +321,8 @@ Open Context Menu Over Cell Editor Place Cursor In Cell Editor At [Arguments] ${cell_nr} ${line} ${character} Enter Cell Editor ${cell_nr} ${line} - Execute JavaScript return document.querySelector('.jp-Cell:nth-child(${cell_nr}) .CodeMirror').CodeMirror.setCursor({line: ${line} - 1, ch: ${character}}) + Execute JavaScript + ... return document.querySelector('.jp-Cell:nth-child(${cell_nr}) .CodeMirror').CodeMirror.setCursor({line: ${line} - 1, ch: ${character}}) Enter File Editor Click Element css:.jp-FileEditor .CodeMirror @@ -319,7 +331,8 @@ Enter File Editor Place Cursor In File Editor At [Arguments] ${line} ${character} Enter File Editor - Execute JavaScript return document.querySelector('.jp-FileEditor .CodeMirror').CodeMirror.setCursor({line: ${line} - 1, ch: ${character}}) + Execute JavaScript + ... return document.querySelector('.jp-FileEditor .CodeMirror').CodeMirror.setCursor({line: ${line} - 1, ch: ${character}}) Wait Until Fully Initialized Wait Until Element Contains ${STATUSBAR} Fully initialized timeout=60s @@ -336,12 +349,12 @@ Open Context Menu Over Context Menu Should Contain [Arguments] ${label} ${timeout}=10s - ${entry} Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')] + ${entry} = Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')] Wait Until Page Contains Element ${entry} timeout=${timeout} Context Menu Should Not Contain [Arguments] ${label} ${timeout}=10s - ${entry} Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')] + ${entry} = Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')] Wait Until Page Does Not Contain Element ${entry} timeout=${timeout} Close Context Menu @@ -393,7 +406,8 @@ Clean Up After Working with File and Settings Jump To Definition [Arguments] ${symbol} - ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] + ${sel} = Set Variable If "${symbol}".startswith(("xpath", "css")) ${symbol} + ... xpath:(//span[@role="presentation"][contains(., "${symbol}")])[last()] Open Context Menu Over ${sel} ${cursor} = Measure Cursor Position Capture Page Screenshot 02-jump-to-definition-0.png @@ -451,8 +465,8 @@ Menus Count Equal Select Menu Entry [Arguments] ${label} - ${entry} Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')] + ${entry} = Set Variable xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), '${label}')] Wait Until Page Contains Element ${entry} timeout=10s Mouse Over ${entry} Click Element ${entry} - Wait Until Page Does Not Contain Element ${entry} timeout=10s \ No newline at end of file + Wait Until Page Does Not Contain Element ${entry} timeout=10s diff --git a/atest/Variables.resource b/atest/Variables.resource new file mode 100644 index 000000000..64333dc47 --- /dev/null +++ b/atest/Variables.resource @@ -0,0 +1,59 @@ +*** Variables *** +${FIXTURES} ${CURDIR}${/}fixtures +${NBSERVER CONF} jupyter_server_config.json +${SPLASH} id:jupyterlab-splash +# to help catch hard-coded paths and encoding issues +${BASE URL} /@est/ +${NOTEBOOK DIR NAME} nöte bòóks +# core paths +${HOME} ${OUTPUT DIR}${/}home +${LAB LOG} ${OUTPUT DIR}${/}lab.log +${GECKODRIVER LOG} ${OUTPUT DIR}${/}geckodriver.log +${SETTINGS DIR} ${OUTPUT DIR}${/}user-settings +${WORKSPACES DIR} ${OUTPUT DIR}${/}workspaces +${NOTEBOOK DIR} ${HOME}${/}${NOTEBOOK DIR NAME} +${VIRTUALDOCS DIR} ${NOTEBOOK DIR}${/}.virtual_documents +${SCREENSHOTS DIR} ${OUTPUT DIR}${/}screenshots +# override with `python scripts/atest.py --variable HEADLESS:0` +${HEADLESS} 1 +${CMD PALETTE INPUT} css:#command-palette .lm-CommandPalette-input +${CMD PALETTE ITEM ACTIVE} css:#command-palette .lm-CommandPalette-item.lm-mod-active +${JLAB XP TOP} //div[@id='jp-top-panel'] +${JLAB XP MENU ITEM LABEL} //div[contains(@class, 'lm-Menu-itemLabel')] +${JLAB XP MENU LABEL} //div[contains(@class, 'lm-MenuBar-itemLabel')] +${JLAB XP DOCK TAB} xpath://div[contains(@class, 'lm-DockPanel-tabBar')]//li[contains(@class, 'lm-TabBar-tab')] +${JLAB CSS VERSION} css:.jp-About-version +${JLAB CSS REFRESH FILES} css:button[title="Refresh File List"] +${CSS DIALOG OK} css:.jp-Dialog .jp-mod-accept +${MENU OPEN WITH} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Open With")] +# R is missing on purpose (may need to use .) +${MENU RENAME} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(., "ename")] +# N is missing on purpose +${MENU NOTEBOOK} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(., "otebook")] +${DIAGNOSTICS PANEL} id:lsp-diagnostics-panel +${DIAGNOSTIC PANEL CLOSE} css:.lm-DockPanel-tabBar .lm-TabBar-tab[data-id="lsp-diagnostics-panel"] .lm-TabBar-tabCloseIcon +${DIALOG WINDOW} css:.jp-Dialog +${DIALOG INPUT} css:.jp-Input-Dialog input +${DIALOG ACCEPT} css:button.jp-Dialog-button.jp-mod-accept +${STATUSBAR} css:div.lsp-statusbar-item +${MENU EDITOR} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(., "Editor")] +${MENU JUMP} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Jump to definition")] +${MENU SETTINGS} xpath://div[contains(@class, 'lm-MenuBar-itemLabel')][contains(text(), "Settings")] +${MENU EDITOR THEME} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Text Editor Theme")] +${LAB MENU} css:.lm-Menu +${CM CURSOR} css:.CodeMirror-cursor +${CM CURSORS} css:.jp-MainAreaWidget:not(.lm-mod-hidden) .CodeMirror-cursors:not([style='visibility: hidden']) +# settings +${LSP PLUGIN ID} @krassowski/jupyterlab-lsp:plugin +${COMPLETION PLUGIN ID} @krassowski/jupyterlab-lsp:completion +${HIGHLIGHTS PLUGIN ID} @krassowski/jupyterlab-lsp:highlights +${JUMP PLUGIN ID} @krassowski/jupyterlab-lsp:jump_to +${DIAGNOSTICS PLUGIN ID} @krassowski/jupyterlab-lsp:diagnostics +${CSS USER SETTINGS} .jp-SettingsRawEditor-user +${JLAB XP CLOSE SETTINGS} ${JLAB XP DOCK TAB}\[contains(., 'Settings')]/*[contains(@class, 'm-TabBar-tabCloseIcon')] +# diagnostics +${CSS DIAGNOSTIC} css:.cm-lsp-diagnostic +# log messages +@{KNOWN BAD ERRORS} +... pylsp_jsonrpc.endpoint - Failed to handle notification +... pylsp_jsonrpc.endpoint - Failed to handle request diff --git a/atest/Variables.robot b/atest/Variables.robot deleted file mode 100644 index eb2603666..000000000 --- a/atest/Variables.robot +++ /dev/null @@ -1,59 +0,0 @@ -*** Variables *** -${FIXTURES} ${CURDIR}${/}fixtures -${NBSERVER CONF} jupyter_server_config.json -${SPLASH} id:jupyterlab-splash -# to help catch hard-coded paths and encoding issues -${BASE URL} /@est/ -${NOTEBOOK DIR NAME} nöte bòóks -# core paths -${HOME} ${OUTPUT DIR}${/}home -${LAB LOG} ${OUTPUT DIR}${/}lab.log -${GECKODRIVER LOG} ${OUTPUT DIR}${/}geckodriver.log -${SETTINGS DIR} ${OUTPUT DIR}${/}user-settings -${WORKSPACES DIR} ${OUTPUT DIR}${/}workspaces -${NOTEBOOK DIR} ${HOME}${/}${NOTEBOOK DIR NAME} -${VIRTUALDOCS DIR} ${NOTEBOOK DIR}${/}.virtual_documents -${SCREENSHOTS DIR} ${OUTPUT DIR}${/}screenshots -# override with `python scripts/atest.py --variable HEADLESS:0` -${HEADLESS} 1 -${CMD PALETTE INPUT} css:#command-palette .lm-CommandPalette-input -${CMD PALETTE ITEM ACTIVE} css:#command-palette .lm-CommandPalette-item.lm-mod-active -${JLAB XP TOP} //div[@id='jp-top-panel'] -${JLAB XP MENU ITEM LABEL} //div[contains(@class, 'lm-Menu-itemLabel')] -${JLAB XP MENU LABEL} //div[contains(@class, 'lm-MenuBar-itemLabel')] -${JLAB XP DOCK TAB} xpath://div[contains(@class, 'lm-DockPanel-tabBar')]//li[contains(@class, 'lm-TabBar-tab')] -${JLAB CSS VERSION} css:.jp-About-version -${JLAB CSS REFRESH FILES} css:button[title="Refresh File List"] -${CSS DIALOG OK} css:.jp-Dialog .jp-mod-accept -${MENU OPEN WITH} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Open With")] -# R is missing on purpose (may need to use .) -${MENU RENAME} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(., "ename")] -# N is missing on purpose -${MENU NOTEBOOK} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(., "otebook")] -${DIAGNOSTICS PANEL} id:lsp-diagnostics-panel -${DIAGNOSTIC PANEL CLOSE} css:.lm-DockPanel-tabBar .lm-TabBar-tab[data-id="lsp-diagnostics-panel"] .lm-TabBar-tabCloseIcon -${DIALOG WINDOW} css:.jp-Dialog -${DIALOG INPUT} css:.jp-Input-Dialog input -${DIALOG ACCEPT} css:button.jp-Dialog-button.jp-mod-accept -${STATUSBAR} css:div.lsp-statusbar-item -${MENU EDITOR} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(., "Editor")] -${MENU JUMP} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Jump to definition")] -${MENU SETTINGS} xpath://div[contains(@class, 'lm-MenuBar-itemLabel')][contains(text(), "Settings")] -${MENU EDITOR THEME} xpath://div[contains(@class, 'lm-Menu-itemLabel')][contains(text(), "Text Editor Theme")] -${LAB MENU} css:.lm-Menu -${CM CURSOR} css:.CodeMirror-cursor -${CM CURSORS} css:.jp-MainAreaWidget:not(.lm-mod-hidden) .CodeMirror-cursors:not([style='visibility: hidden']) -# settings -${LSP PLUGIN ID} @krassowski/jupyterlab-lsp:plugin -${COMPLETION PLUGIN ID} @krassowski/jupyterlab-lsp:completion -${HIGHLIGHTS PLUGIN ID} @krassowski/jupyterlab-lsp:highlights -${JUMP PLUGIN ID} @krassowski/jupyterlab-lsp:jump_to -${DIAGNOSTICS PLUGIN ID} @krassowski/jupyterlab-lsp:diagnostics -${CSS USER SETTINGS} .jp-SettingsRawEditor-user -${JLAB XP CLOSE SETTINGS} ${JLAB XP DOCK TAB}\[contains(., 'Settings')]/*[contains(@class, 'm-TabBar-tabCloseIcon')] -# diagnostics -${CSS DIAGNOSTIC} css:.cm-lsp-diagnostic -# log messages -@{KNOWN BAD ERRORS} -... pylsp_jsonrpc.endpoint - Failed to handle notification -... pylsp_jsonrpc.endpoint - Failed to handle request diff --git a/atest/__init__.robot b/atest/__init__.robot index 4cc357221..86c3f01aa 100644 --- a/atest/__init__.robot +++ b/atest/__init__.robot @@ -1,7 +1,9 @@ *** Settings *** -Suite Setup Setup Server and Browser -Suite Teardown Tear Down Everything -Test Setup Reset Application State -Test Teardown Lab Log Should Not Contain Known Error Messages -Force Tags os:${OS.lower()} py:${PY} -Resource Keywords.robot +Resource Keywords.resource + +Suite Setup Setup Server and Browser +Suite Teardown Tear Down Everything +Test Setup Reset Application State +Test Teardown Lab Log Should Not Contain Known Error Messages + +Force Tags os:${os.lower()} py:${py} diff --git a/atest/examples/example.robot b/atest/examples/example.robot new file mode 100644 index 000000000..11b65d220 --- /dev/null +++ b/atest/examples/example.robot @@ -0,0 +1,17 @@ +*** Settings *** +Library SeleniumLibrary +Force Tags atest:example + +*** Variables *** +${ABC} abc + +*** Keywords *** +Special Log + [Arguments] ${log} + [Documentation] a special log + Log ${log.upper()}! + +*** Test Cases *** +Log Something + Special Log ${ABC} + Something that doesn't exist diff --git a/binder/environment.yml b/binder/environment.yml index 94043a96c..7898880a8 100644 --- a/binder/environment.yml +++ b/binder/environment.yml @@ -33,3 +33,8 @@ dependencies: - tectonic - texlab - chktex + # robotframework + - jupyterlab_robotmode + - robotframework-lsp + - robotframework-robocop + - robotkernel diff --git a/binder/overrides.json b/binder/overrides.json new file mode 100644 index 000000000..a9c9132bf --- /dev/null +++ b/binder/overrides.json @@ -0,0 +1,21 @@ +{ + "@krassowski/jupyterlab-lsp:plugin": { + "language_servers": { + "robotframework_ls": { + "serverSettings": { + "robot.lint.robocop.enabled": true + } + }, + "texlab": { + "serverSettings": { + "latex.lint.onChange": true + } + }, + "pyright": { + "serverSettings": { + "python.analysis.useLibraryCodeForTypes": true + } + } + } + } +} diff --git a/binder/postBuild b/binder/postBuild index c0fd44d77..f0ca4bec2 100755 --- a/binder/postBuild +++ b/binder/postBuild @@ -6,18 +6,24 @@ jlpm bootstrap # Do a dev install of the server side pushd python_packages/jupyter_lsp -python setup.py sdist bdist_wheel -python -m pip install -e . --ignore-installed --no-deps -vv -jupyter serverextension enable --sys-prefix --py jupyter_lsp + python setup.py sdist bdist_wheel + python -m pip install -e . --ignore-installed --no-deps -vv + jupyter serverextension enable --sys-prefix --py jupyter_lsp popd # Install the labextension pushd python_packages/jupyterlab_lsp -python setup.py sdist bdist_wheel -python -m pip install -e . --ignore-installed --no-deps -vv -jupyter labextension develop . --overwrite + python setup.py sdist bdist_wheel + python -m pip install -e . --ignore-installed --no-deps -vv + jupyter labextension develop . --overwrite popd + # List extensions jupyter serverextension list jupyter server extension list jupyter labextension list + +if [ "$NB_USER" = "jovyan" ]; then + mkdir -p $NB_PYTHON_PREFIX/share/jupyter/lab/settings/ + cp binder/overrides.json $NB_PYTHON_PREFIX/share/jupyter/lab/settings/ +fi diff --git a/docs/Language Servers.ipynb b/docs/Language Servers.ipynb index 398891cf3..e964b8c10 100644 --- a/docs/Language Servers.ipynb +++ b/docs/Language Servers.ipynb @@ -135,11 +135,11 @@ "source": [ "### Notebook-optimized Language Servers\n", "\n", - "These servers have support for notebooks and file editors. The `pyls` and\n", - "`r-languageserver` are well-tested, while `jedi` and `Julia` servers are\n", - "experimental. If you choose to install multiple language servers for the same\n", - "language, the one with the highest `priority` (which can be set in the _Advanced\n", - "Settings Editor_) will be used." + "These servers have support for notebooks and file editors. The `pylsp`, and\n", + "`r-languageserver`, and `robotframework_ls` implementatoons are well-tested,\n", + "while `jedi` and `Julia` servers are experimental. If you choose to install\n", + "multiple language servers for the same language, the one with the highest\n", + "`priority` (which can be set in the _Advanced Settings Editor_) will be used." ] }, { @@ -158,9 +158,14 @@ " \"r-languageserver\",\n", " \"julia-language-server\",\n", " \"jedi-language-server\",\n", + " \"robotframework_ls\",\n", "]\n", "lang_server_table(\n", - " {key: spec for key, spec in mgr.all_language_servers.items() if key in nb_langs}\n", + " {\n", + " key: spec\n", + " for key, spec in sorted(mgr.all_language_servers.items())\n", + " if key in nb_langs\n", + " }\n", ")" ] }, @@ -203,21 +208,21 @@ }, "outputs": [], "source": [ - "lang_server_table(\n", - " {\n", - " key: spec\n", - " for key, spec in mgr.all_language_servers.items()\n", - " if \"npm\" in spec[\"install\"]\n", - " }\n", - ")" + "npm_specs = {\n", + " key: spec\n", + " for key, spec in sorted(mgr.all_language_servers.items())\n", + " if \"npm\" in spec[\"install\"]\n", + "}\n", + "lang_server_table(npm_specs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "NodeJS is a prerequisite for installation of any of the above language servers;\n", - "you can get it with:\n", + "NodeJS (preferrably even-numbered an _Active_ or _Maintenance Long Term Support_\n", + "release) is a prerequisite for installation of any of the above language\n", + "servers; you can get it with:\n", "\n", "```bash\n", "conda install -c conda-forge nodejs\n", @@ -242,19 +247,34 @@ "`node_modules` in the directory where you launch `jupyter lab`.\n", "\n", "For example, to install all the servers which are tested as part of\n", - "`jupyterlab-lsp`:\n", - "\n", - "```bash\n", - "jlpm add --dev \\\n", - " bash-language-server \\\n", - " vscode-css-languageserver-bin \\\n", - " dockerfile-language-server-nodejs \\\n", - " vscode-html-languageserver-bin \\\n", - " typescript-language-server \\\n", - " vscode-json-languageserver-bin \\\n", - " yaml-language-server\n", + "`jupyterlab-lsp`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-input" + ] + }, + "outputs": [], + "source": [ + "IPython.display.Markdown(\n", + " Template(\n", + " \"\"\"```bash\n", + "jlpm add --dev {% for name, spec in specs.items() %} \\\\\n", + " {{ spec[\"install\"][\"npm\"].split(\" \")[-1] }}{% endfor %}\n", "```\n", - "\n", + "\"\"\"\n", + " ).render(specs=npm_specs)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "This will create (or add to):\n", "\n", "- `package.json` (check this in!)\n", @@ -369,9 +389,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.9" + "version": "3.10.0" } }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/docs/rtd.yml b/docs/rtd.yml index 47c5cc0d3..3769ddd43 100644 --- a/docs/rtd.yml +++ b/docs/rtd.yml @@ -16,6 +16,7 @@ dependencies: - python >=3.7,<3.11.0a0 - python-graphviz - python-lsp-server + - robotframework-lsp - sphinx - sphinx-autodoc-typehints - sphinx-book-theme diff --git a/requirements/atest.txt b/requirements/atest.txt index 05050a144..af451542b 100644 --- a/requirements/atest.txt +++ b/requirements/atest.txt @@ -2,4 +2,6 @@ -r ./lab.txt bs4 robotframework >=4 +robotframework-lsp robotframework-seleniumlibrary +robotkernel diff --git a/requirements/atest.yml b/requirements/atest.yml index b6cae423e..436a6ff18 100644 --- a/requirements/atest.yml +++ b/requirements/atest.yml @@ -5,7 +5,9 @@ channels: - nodefaults dependencies: - - robotframework-seleniumlibrary - - robotframework >=4 - firefox - geckodriver + - jupyterlab_robotmode + - robotframework >=4 + - robotframework-seleniumlibrary + - robotkernel diff --git a/requirements/dev.txt b/requirements/dev.txt index 0caa297b2..ec4df2fef 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -6,6 +6,7 @@ pyls-isort pyls-mypy pytest-cov ruamel.yaml -robotframework-lint >=1.1 -robotframework >=3.2 +robotframework-robocop +robotframework-tidy +robotframework >=4 types-six diff --git a/requirements/github-actions.yml b/requirements/github-actions.yml index 8e8ef2eaa..603ff7491 100644 --- a/requirements/github-actions.yml +++ b/requirements/github-actions.yml @@ -10,9 +10,15 @@ dependencies: - pip - nodejs {nodejs} # for python language server (and development) + - python-lsp-server - flake8 >=3.5 - # temporarily pin autopep8 - autopep8 <1.6.0 + # robotframework for testing and language server + - jupyterlab_robotmode + - robotframework >=4 + - robotframework-lsp + - robotframework-robocop + - robotkernel # for R language server and kernel - r {r} - r-irkernel @@ -34,6 +40,4 @@ dependencies: - bs4 - firefox - geckodriver - - robotframework >=4 - robotframework-seleniumlibrary - - python-lsp-server diff --git a/requirements/lint.yml b/requirements/lint.yml index f12dee91b..f89b01cb8 100644 --- a/requirements/lint.yml +++ b/requirements/lint.yml @@ -5,11 +5,11 @@ channels: - nodefaults dependencies: - - pip - black - isort - mypy - - robotframework-lint >=1.1 - - robotframework >=4,<4.1 + - pip - pytest-tornasync + - robotframework-robocop + - robotframework-tidy - types-six diff --git a/scripts/atest.py b/scripts/atest.py index 80b2125c8..7eb8a27be 100644 --- a/scripts/atest.py +++ b/scripts/atest.py @@ -22,7 +22,7 @@ # notebook and ipykernel releases do not yet support python 3.8 on windows # ("Windows", "38"): ["--include", "not-supported", "--runemptysuite"] # TODO: restore when we figure out win36 vs jedi on windows - ("Windows", "36"): ["--exclude", "feature:completion", "--runemptysuite"] + # ("Windows", "36"): ["--exclude", "feature:completion", "--runemptysuite"] } NON_CRITICAL = [ @@ -30,7 +30,7 @@ # everything else: https://github.com/jupyter-lsp/jupyterlab-lsp/pull/245 ["language:yaml", "feature:config"], # TODO: restore when we figure out win36 vs jedi on windows - ["language:python", "py:36", "os:windows"], + # ["language:python", "py:36", "os:windows"], ] @@ -100,6 +100,10 @@ def atest(attempt, extra_args): f"OS:{OS}", "--variable", f"PY:{PY}", + # don't ever test our examples + "--exclude", + "atest:example", + # random ensures there's not inter-test coupling "--randomize", "all", *(extra_args or []), diff --git a/scripts/lint.py b/scripts/lint.py index ab37c131d..32cbf5fa1 100644 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -28,26 +28,36 @@ ALL_PY = [*PY_SRC, *PY_SCRIPTS, *PY_ATEST, *PY_DOCS] -ALL_ROBOT = list((ROOT / "atest").rglob("*.robot")) - -RFLINT_RULES = [ - "LineTooLong:200", - "TooFewKeywordSteps:0", - "TooFewTestSteps:1", - "TooManyTestSteps:30", - "TooManyTestCases:30", - "FileTooLong:400", +ALL_ROBOT = [ + r + for ext in ["robot", "resource"] + for r in (ROOT / "atest").rglob(f"*.{ext}") + if not (r.name in ["example.robot"] or "checkpoint" in str(r)) ] -RFLINT_IGNORES = [ - "RequireKeywordDocumentation", - "RequireSuiteDocumentation", - "RequireTestDocumentation", + +# TODO: explore adopting these conventions +ROBOCOP_EXCLUDES = [ + "empty-lines-between-sections", + "file-too-long", + "if-can-be-used", + "missing-doc-keyword", + "missing-doc-suite", + "missing-doc-test-case", + "too-long-test-case", + "too-many-arguments", + "too-many-calls-in-keyword", + "too-many-calls-in-test-case", + "wrong-case-in-keyword-name", ] -RFLINT = sum( - [["--configure", rule] for rule in RFLINT_RULES] - + [["--ignore", rule] for rule in RFLINT_IGNORES], +ROBOCOP_CONFIGS = ["line-too-long:line_length:200"] + +ROBOCOP = sum( + [ + *[["--exclude", e] for e in ROBOCOP_EXCLUDES], + *[["--configure", c] for c in ROBOCOP_CONFIGS], + ], [], ) @@ -55,12 +65,21 @@ def lint(): """get that linty fresh feeling""" + def call_with_print(args): + str_args = [a for a in args if isinstance(a, str)] + paths = [a for a in args if isinstance(a, Path)] + print(f"{len(paths)} paths:", " ".join(str_args)) + return_code = call(list(map(str, args))) + if return_code: + print("\n...", f"ERROR {return_code}", *str_args, "\n") + return return_code + return max( map( - call, + call_with_print, [ ["isort", *ALL_PY], - ["black", *ALL_PY], + ["black", "--quiet", *ALL_PY], ["flake8", *ALL_PY], *[ # see https://github.com/python/mypy/issues/4008 @@ -68,8 +87,8 @@ def lint(): for paths in PY_SRC_PACKAGES.values() ], # ["pylint", *ALL_PY], - ["python", "-m", "robot.tidy", "--inplace", *ALL_ROBOT], - ["rflint", *RFLINT, *ALL_ROBOT], + ["robotidy", *ALL_ROBOT], + ["robocop", *ROBOCOP, *ALL_ROBOT], ["python", "scripts/atest.py", "--dryrun", "--console", "dotted"], ["python", "scripts/nblint.py"], ],