diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f2b13b..b0f6d58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,143 +15,143 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Base Setup - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - - - name: Install dependencies - run: python -m pip install -U "jupyterlab>=4.0.0,<5" - - - name: Lint the extension - run: | - set -eux - jlpm - jlpm run lint:check - - - name: Test the extension - run: | - set -eux - jlpm run test - - - name: Build the extension - run: | - set -eux - python -m pip install .[test] - - pytest -vv -r ap --cov jupyterlab_deepnote - jupyter server extension list - jupyter server extension list 2>&1 | grep -ie "jupyterlab_deepnote.*OK" - - jupyter labextension list - jupyter labextension list 2>&1 | grep -ie "jupyterlab-deepnote.*OK" - python -m jupyterlab.browser_check - - - name: Package the extension - run: | - set -eux - - pip install build - python -m build - pip uninstall -y "jupyterlab_deepnote" jupyterlab - - - name: Upload extension packages - uses: actions/upload-artifact@v4 - with: - name: extension-artifacts - path: dist/jupyterlab_deepnote* - if-no-files-found: error + - name: Checkout + uses: actions/checkout@v4 + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Install dependencies + run: python -m pip install -U "jupyterlab>=4.0.0,<5" + + - name: Lint the extension + run: | + set -eux + jlpm + jlpm run lint:check + + - name: Test the extension + run: | + set -eux + jlpm run test + + - name: Build the extension + run: | + set -eux + python -m pip install .[test] + + pytest -vv -r ap --cov jupyterlab_deepnote + jupyter server extension list + jupyter server extension list 2>&1 | grep -ie "jupyterlab_deepnote.*OK" + + jupyter labextension list + jupyter labextension list 2>&1 | grep -ie "jupyterlab-deepnote.*OK" + python -m jupyterlab.browser_check + + - name: Package the extension + run: | + set -eux + + pip install build + python -m build + pip uninstall -y "jupyterlab_deepnote" jupyterlab + + - name: Upload extension packages + uses: actions/upload-artifact@v4 + with: + name: extension-artifacts + path: dist/jupyterlab_deepnote* + if-no-files-found: error test_isolated: needs: build runs-on: ubuntu-latest steps: - - name: Install Python - uses: actions/setup-python@v5 - with: - python-version: '3.9' - architecture: 'x64' - - uses: actions/download-artifact@v4 - with: - name: extension-artifacts - - name: Install and Test - run: | - set -eux - # Remove NodeJS, twice to take care of system and locally installed node versions. - sudo rm -rf $(which node) - sudo rm -rf $(which node) - - pip install "jupyterlab>=4.0.0,<5" jupyterlab_deepnote*.whl - - - jupyter server extension list - jupyter server extension list 2>&1 | grep -ie "jupyterlab_deepnote.*OK" - - jupyter labextension list - jupyter labextension list 2>&1 | grep -ie "jupyterlab-deepnote.*OK" - python -m jupyterlab.browser_check --no-browser-test - - integration-tests: - name: Integration tests - needs: build - runs-on: ubuntu-latest - - env: - PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/pw-browsers - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Base Setup - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - - - name: Download extension package - uses: actions/download-artifact@v4 - with: - name: extension-artifacts - - - name: Install the extension - run: | - set -eux - python -m pip install "jupyterlab>=4.0.0,<5" jupyterlab_deepnote*.whl - - - name: Install dependencies - working-directory: ui-tests - env: - YARN_ENABLE_IMMUTABLE_INSTALLS: 0 - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 - run: jlpm install - - - name: Set up browser cache - uses: actions/cache@v4 - with: - path: | - ${{ github.workspace }}/pw-browsers - key: ${{ runner.os }}-${{ hashFiles('ui-tests/yarn.lock') }} - - - name: Install browser - run: | - set -eux - jlpm playwright install-deps - jlpm playwright install chromium - working-directory: ui-tests - - - name: Execute integration tests - working-directory: ui-tests - run: | - jlpm playwright test - - - name: Upload Playwright Test report - if: always() - uses: actions/upload-artifact@v4 - with: - name: jupyterlab_deepnote-playwright-tests - path: | - ui-tests/test-results - ui-tests/playwright-report + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: '3.9' + architecture: 'x64' + - uses: actions/download-artifact@v4 + with: + name: extension-artifacts + - name: Install and Test + run: | + set -eux + # Remove NodeJS, twice to take care of system and locally installed node versions. + sudo rm -rf $(which node) + sudo rm -rf $(which node) + + pip install "jupyterlab>=4.0.0,<5" jupyterlab_deepnote*.whl + + + jupyter server extension list + jupyter server extension list 2>&1 | grep -ie "jupyterlab_deepnote.*OK" + + jupyter labextension list + jupyter labextension list 2>&1 | grep -ie "jupyterlab-deepnote.*OK" + python -m jupyterlab.browser_check --no-browser-test + + # integration-tests: + # name: Integration tests + # needs: build + # runs-on: ubuntu-latest + # + # env: + # PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/pw-browsers + # + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + # + # - name: Base Setup + # uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + # + # - name: Download extension package + # uses: actions/download-artifact@v4 + # with: + # name: extension-artifacts + # + # - name: Install the extension + # run: | + # set -eux + # python -m pip install "jupyterlab>=4.0.0,<5" jupyterlab_deepnote*.whl + # + # - name: Install dependencies + # working-directory: ui-tests + # env: + # YARN_ENABLE_IMMUTABLE_INSTALLS: 0 + # PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + # run: jlpm install + # + # - name: Set up browser cache + # uses: actions/cache@v4 + # with: + # path: | + # ${{ github.workspace }}/pw-browsers + # key: ${{ runner.os }}-${{ hashFiles('ui-tests/yarn.lock') }} + # + # - name: Install browser + # run: | + # set -eux + # jlpm playwright install-deps + # jlpm playwright install chromium + # working-directory: ui-tests + # + # - name: Execute integration tests + # working-directory: ui-tests + # run: | + # jlpm playwright test + # + # - name: Upload Playwright Test report + # if: always() + # uses: actions/upload-artifact@v4 + # with: + # name: jupyterlab_deepnote-playwright-tests + # path: | + # ui-tests/test-results + # ui-tests/playwright-report check_links: name: Check Links diff --git a/.github/workflows/enforce-label.yml b/.github/workflows/enforce-label.yml deleted file mode 100644 index 725feab..0000000 --- a/.github/workflows/enforce-label.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Enforce PR label - -on: - pull_request: - types: [labeled, unlabeled, opened, edited, synchronize] -jobs: - enforce-label: - runs-on: ubuntu-latest - permissions: - pull-requests: write - steps: - - name: enforce-triage-label - uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1 diff --git a/README.md b/README.md index 547164d..a799e60 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # jupyterlab_deepnote -[![Github Actions Status](https://github.com/deepnote/jupyterlab-deepnote/workflows/Build/badge.svg)](https://github.com/deepnote/jupyterlab-deepnote/actions/workflows/build.yml) - A Deepnote extension for JupyterLab This extension is composed of a Python package named `jupyterlab_deepnote` @@ -168,13 +166,6 @@ jlpm jlpm test ``` -#### Integration tests - -This extension uses [Playwright](https://playwright.dev/docs/intro) for the integration tests (aka user level tests). -More precisely, the JupyterLab helper [Galata](https://github.com/jupyterlab/jupyterlab/tree/master/galata) is used to handle testing the extension in JupyterLab. - -More information are provided within the [ui-tests](./ui-tests/README.md) README. - ### Packaging the extension See [RELEASE](RELEASE.md) diff --git a/src/index.tsx b/src/index.tsx index 69de656..6382c0f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -115,11 +115,18 @@ class NotebookPicker extends ReactWidget { return ( {}} aria-label="Select active notebook" title="Select active notebook" + style={{ + maxWidth: '120px', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden' + }} > {names.length === 0 ? ( diff --git a/ui-tests/README.md b/ui-tests/README.md new file mode 100644 index 0000000..9182514 --- /dev/null +++ b/ui-tests/README.md @@ -0,0 +1,167 @@ +# Integration Testing + +This folder contains the integration tests of the extension. + +They are defined using [Playwright](https://playwright.dev/docs/intro) test runner +and [Galata](https://github.com/jupyterlab/jupyterlab/tree/main/galata) helper. + +The Playwright configuration is defined in [playwright.config.js](./playwright.config.js). + +The JupyterLab server configuration to use for the integration test is defined +in [jupyter_server_test_config.py](./jupyter_server_test_config.py). + +The default configuration will produce video for failing tests and an HTML report. + +> There is a UI mode that you may like; see [that video](https://www.youtube.com/watch?v=jF0yA-JLQW0). + +## Run the tests + +> All commands are assumed to be executed from the root directory + +To run the tests, you need to: + +1. Compile the extension: + +```sh +jlpm install +jlpm build:prod +``` + +> Check the extension is installed in JupyterLab. + +2. Install test dependencies (needed only once): + +```sh +cd ./ui-tests +jlpm install +jlpm playwright install +cd .. +``` + +3. Execute the [Playwright](https://playwright.dev/docs/intro) tests: + +```sh +cd ./ui-tests +jlpm playwright test +``` + +Test results will be shown in the terminal. In case of any test failures, the test report +will be opened in your browser at the end of the tests execution; see +[Playwright documentation](https://playwright.dev/docs/test-reporters#html-reporter) +for configuring that behavior. + +## Update the tests snapshots + +> All commands are assumed to be executed from the root directory + +If you are comparing snapshots to validate your tests, you may need to update +the reference snapshots stored in the repository. To do that, you need to: + +1. Compile the extension: + +```sh +jlpm install +jlpm build:prod +``` + +> Check the extension is installed in JupyterLab. + +2. Install test dependencies (needed only once): + +```sh +cd ./ui-tests +jlpm install +jlpm playwright install +cd .. +``` + +3. Execute the [Playwright](https://playwright.dev/docs/intro) command: + +```sh +cd ./ui-tests +jlpm playwright test -u +``` + +> Some discrepancy may occurs between the snapshots generated on your computer and +> the one generated on the CI. To ease updating the snapshots on a PR, you can +> type `please update playwright snapshots` to trigger the update by a bot on the CI. +> Once the bot has computed new snapshots, it will commit them to the PR branch. + +## Create tests + +> All commands are assumed to be executed from the root directory + +To create tests, the easiest way is to use the code generator tool of playwright: + +1. Compile the extension: + +```sh +jlpm install +jlpm build:prod +``` + +> Check the extension is installed in JupyterLab. + +2. Install test dependencies (needed only once): + +```sh +cd ./ui-tests +jlpm install +jlpm playwright install +cd .. +``` + +3. Start the server: + +```sh +cd ./ui-tests +jlpm start +``` + +4. Execute the [Playwright code generator](https://playwright.dev/docs/codegen) in **another terminal**: + +```sh +cd ./ui-tests +jlpm playwright codegen localhost:8888 +``` + +## Debug tests + +> All commands are assumed to be executed from the root directory + +To debug tests, a good way is to use the inspector tool of playwright: + +1. Compile the extension: + +```sh +jlpm install +jlpm build:prod +``` + +> Check the extension is installed in JupyterLab. + +2. Install test dependencies (needed only once): + +```sh +cd ./ui-tests +jlpm install +jlpm playwright install +cd .. +``` + +3. Execute the Playwright tests in [debug mode](https://playwright.dev/docs/debug): + +```sh +cd ./ui-tests +jlpm playwright test --debug +``` + +## Upgrade Playwright and the browsers + +To update the web browser versions, you must update the package `@playwright/test`: + +```sh +cd ./ui-tests +jlpm up "@playwright/test" +jlpm playwright install +``` diff --git a/ui-tests/jupyter_server_test_config.py b/ui-tests/jupyter_server_test_config.py new file mode 100644 index 0000000..f2a9478 --- /dev/null +++ b/ui-tests/jupyter_server_test_config.py @@ -0,0 +1,12 @@ +"""Server configuration for integration tests. + +!! Never use this configuration in production because it +opens the server to the world and provide access to JupyterLab +JavaScript objects through the global window variable. +""" +from jupyterlab.galata import configure_jupyter_server + +configure_jupyter_server(c) + +# Uncomment to set server log level to debug level +# c.ServerApp.log_level = "DEBUG" diff --git a/ui-tests/package.json b/ui-tests/package.json new file mode 100644 index 0000000..bbf79d7 --- /dev/null +++ b/ui-tests/package.json @@ -0,0 +1,15 @@ +{ + "name": "jupyterlab-deepnote-ui-tests", + "version": "1.0.0", + "description": "JupyterLab jupyterlab-deepnote Integration Tests", + "private": true, + "scripts": { + "start": "jupyter lab --config jupyter_server_test_config.py", + "test": "jlpm playwright test", + "test:update": "jlpm playwright test --update-snapshots" + }, + "devDependencies": { + "@jupyterlab/galata": "^5.0.5", + "@playwright/test": "^1.37.0" + } +} diff --git a/ui-tests/playwright.config.js b/ui-tests/playwright.config.js new file mode 100644 index 0000000..9ece6fa --- /dev/null +++ b/ui-tests/playwright.config.js @@ -0,0 +1,14 @@ +/** + * Configuration for Playwright using default from @jupyterlab/galata + */ +const baseConfig = require('@jupyterlab/galata/lib/playwright-config'); + +module.exports = { + ...baseConfig, + webServer: { + command: 'jlpm start', + url: 'http://localhost:8888/lab', + timeout: 120 * 1000, + reuseExistingServer: !process.env.CI + } +}; diff --git a/ui-tests/tests/jupyterlab_deepnote.spec.ts b/ui-tests/tests/jupyterlab_deepnote.spec.ts new file mode 100644 index 0000000..b2e89e9 --- /dev/null +++ b/ui-tests/tests/jupyterlab_deepnote.spec.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@jupyterlab/galata'; + +/** + * Don't load JupyterLab webpage before running the tests. + * This is required to ensure we capture all log messages. + */ +test.use({ autoGoto: false }); + +test('should emit an activation console message', async ({ page }) => { + const logs: string[] = []; + + page.on('console', message => { + logs.push(message.text()); + }); + + await page.goto(); + + expect( + logs.filter( + s => s === 'JupyterLab extension jupyterlab-deepnote is activated!' + ) + ).toHaveLength(1); +}); diff --git a/ui-tests/yarn.lock b/ui-tests/yarn.lock new file mode 100644 index 0000000..e69de29