├── .eslintignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug-reports.yml │ ├── config.yml │ ├── feature-requests.yml │ └── tasks.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── release.yml └── workflows │ ├── coverage.yml │ ├── insiders.yml │ ├── main.yml │ ├── nodejs.yml │ ├── publish-wiki.yml │ ├── stalebot.yml │ └── template-main.yaml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DCO ├── KNOWN_ISSUES.md ├── LICENSE ├── README.md ├── SECURITY.md ├── docs ├── ActionsControl.md ├── ActivityBar.md ├── BottomBarPanel.md ├── CodeCoverage.md ├── ContentAssist.md ├── ContextMenu.md ├── ContextMenuItem.md ├── CustomEditor.md ├── CustomTreeSection.md ├── DebugConsoleView.md ├── DebugToolbar.md ├── DebugView.md ├── Debugging-Tests.md ├── DefaultTreeSection.md ├── DiffEditor.md ├── EditorView.md ├── ExtensionEditorDetailsSections.md ├── ExtensionEditorView.md ├── ExtensionsViewSection.md ├── FindWidget.md ├── Home.md ├── Input.md ├── Mocha-Configuration.md ├── ModalDialog.md ├── Notification.md ├── NotificationsCenter.md ├── OutputView.md ├── Page-Object-APIs.md ├── ProblemsView.md ├── ScmView.md ├── Setting.md ├── SettingsEditor.md ├── SideBarView.md ├── StatusBar.md ├── Taking Screenshots.md ├── TerminalView.md ├── Test-Setup.md ├── TextEditor.md ├── TitleBar.md ├── TitleBarItem.md ├── ViewContent.md ├── ViewControl.md ├── ViewItem.md ├── ViewSection.md ├── ViewTitlePart.md ├── WebView.md ├── WebviewView.md ├── WindowControls.md ├── Workbench.md ├── Writing-Simple-Tests.md └── images │ ├── debugView-CallStack.png │ ├── debugView-Variables.png │ ├── debugView-WatchSection.png │ ├── editorActions-dropdown.png │ ├── quickInputAction.png │ ├── viewActions-dropdown.png │ └── webview-view-example.png ├── eslint.config.js ├── icons ├── extester-card.png ├── logo-text-bottom.png ├── logo-text-side.png └── logo.png ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── extester │ ├── README.md │ ├── package.json │ ├── resources │ │ └── state.vscdb │ ├── src │ │ ├── browser.ts │ │ ├── cli.ts │ │ ├── extester.ts │ │ ├── suite │ │ │ ├── mochaHooks.ts │ │ │ └── runner.ts │ │ └── util │ │ │ ├── codeUtil.ts │ │ │ ├── coverage.ts │ │ │ ├── download.ts │ │ │ ├── driverUtil.ts │ │ │ └── unpack.ts │ └── tsconfig.json ├── locators │ ├── README.md │ ├── index.ts │ ├── lib │ │ ├── 1.100.0.ts │ │ ├── 1.37.0.ts │ │ ├── 1.38.0.ts │ │ ├── 1.39.0.ts │ │ ├── 1.40.0.ts │ │ ├── 1.41.0.ts │ │ ├── 1.43.0.ts │ │ ├── 1.44.0.ts │ │ ├── 1.45.0.ts │ │ ├── 1.46.0.ts │ │ ├── 1.47.0.ts │ │ ├── 1.49.0.ts │ │ ├── 1.50.0.ts │ │ ├── 1.52.0.ts │ │ ├── 1.54.0.ts │ │ ├── 1.56.0.ts │ │ ├── 1.57.0.ts │ │ ├── 1.59.0.ts │ │ ├── 1.60.0.ts │ │ ├── 1.61.0.ts │ │ ├── 1.66.0.ts │ │ ├── 1.70.0.ts │ │ ├── 1.71.0.ts │ │ ├── 1.73.0.ts │ │ ├── 1.83.0.ts │ │ ├── 1.84.0.ts │ │ ├── 1.85.0.ts │ │ ├── 1.87.0.ts │ │ ├── 1.88.0.ts │ │ ├── 1.90.0.ts │ │ ├── 1.98.0.ts │ │ └── 1.99.0.ts │ ├── package.json │ └── tsconfig.json └── page-objects │ ├── README.md │ ├── package.json │ ├── src │ ├── components │ │ ├── AbstractElement.ts │ │ ├── ActionButtonElementDropdown.ts │ │ ├── ElementWithContextMenu.ts │ │ ├── WebviewMixin.ts │ │ ├── activityBar │ │ │ ├── ActionsControl.ts │ │ │ ├── ActivityBar.ts │ │ │ └── ViewControl.ts │ │ ├── bottomBar │ │ │ ├── AbstractViews.ts │ │ │ ├── BottomBarPanel.ts │ │ │ ├── ProblemsView.ts │ │ │ ├── Views.ts │ │ │ └── WebviewView.ts │ │ ├── dialog │ │ │ └── ModalDialog.ts │ │ ├── editor │ │ │ ├── Breakpoint.ts │ │ │ ├── ContentAssist.ts │ │ │ ├── CustomEditor.ts │ │ │ ├── DiffEditor.ts │ │ │ ├── Editor.ts │ │ │ ├── EditorAction.ts │ │ │ ├── EditorView.ts │ │ │ ├── ExtensionEditorDetailsSection.ts │ │ │ ├── ExtensionEditorView.ts │ │ │ ├── SettingsEditor.ts │ │ │ ├── TextEditor.ts │ │ │ └── WebView.ts │ │ ├── menu │ │ │ ├── ContextMenu.ts │ │ │ ├── MacTitleBar.ts │ │ │ ├── Menu.ts │ │ │ ├── MenuItem.ts │ │ │ ├── TitleBar.ts │ │ │ └── WindowControls.ts │ │ ├── sidebar │ │ │ ├── SideBarView.ts │ │ │ ├── ViewContent.ts │ │ │ ├── ViewItem.ts │ │ │ ├── ViewSection.ts │ │ │ ├── ViewTitlePart.ts │ │ │ ├── WelcomeContent.ts │ │ │ ├── debug │ │ │ │ └── DebugView.ts │ │ │ ├── extensions │ │ │ │ ├── ExtensionsViewItem.ts │ │ │ │ └── ExtensionsViewSection.ts │ │ │ ├── scm │ │ │ │ ├── NewScmView.ts │ │ │ │ └── ScmView.ts │ │ │ └── tree │ │ │ │ ├── TreeSection.ts │ │ │ │ ├── custom │ │ │ │ ├── CustomTreeItem.ts │ │ │ │ └── CustomTreeSection.ts │ │ │ │ ├── debug │ │ │ │ ├── BreakpointSectionItem.ts │ │ │ │ ├── CallStackItem.ts │ │ │ │ ├── DebugBreakpointSection.ts │ │ │ │ ├── DebugCallStackSection.ts │ │ │ │ ├── DebugVariablesSection.ts │ │ │ │ ├── SectionBreakpoint.ts │ │ │ │ ├── VariableSectionItem.ts │ │ │ │ ├── WatchSection.ts │ │ │ │ └── WatchSectionItem.ts │ │ │ │ └── default │ │ │ │ ├── DefaultTreeItem.ts │ │ │ │ └── DefaultTreeSection.ts │ │ ├── statusBar │ │ │ └── StatusBar.ts │ │ └── workbench │ │ │ ├── DebugToolbar.ts │ │ │ ├── Notification.ts │ │ │ ├── NotificationsCenter.ts │ │ │ ├── Workbench.ts │ │ │ └── input │ │ │ ├── Input.ts │ │ │ ├── InputBox.ts │ │ │ └── QuickOpenBox.ts │ ├── conditions │ │ └── WaitForAttribute.ts │ ├── errors │ │ └── NullAttributeError.ts │ ├── index.ts │ └── locators │ │ ├── loader.ts │ │ └── locators.ts │ └── tsconfig.json ├── tests └── test-project │ ├── .gitignore │ ├── .mocharc-debug.js │ ├── .mocharc.js │ ├── .vscode │ └── settings.json │ ├── .vscodeignore │ ├── LICENSE │ ├── README.md │ ├── icons │ └── logo.png │ ├── media │ ├── catScratch.css │ ├── catScratch.js │ ├── paw-color.svg │ ├── paw-outline.svg │ ├── pawDraw.css │ ├── pawDraw.js │ ├── reset.css │ ├── sand-dark.jpg │ ├── sand.jpg │ └── vscode.css │ ├── package.json │ ├── resources │ ├── debug-project │ │ ├── .vscode │ │ │ └── launch.json │ │ └── test.js │ ├── example.cscratch │ ├── file-with-spaces.ts │ ├── file-with-tabs.ts │ ├── icons │ │ ├── dark │ │ │ └── refresh.svg │ │ └── light │ │ │ └── refresh.svg │ ├── test-file-a.txt │ ├── test-file-b.txt │ ├── test-file.ts │ └── test-folder │ │ ├── foo │ │ └── foolder │ │ └── bar │ ├── src │ ├── catScratchEditor.ts │ ├── codelensProvider.ts │ ├── extension.ts │ ├── test │ │ ├── 01_general │ │ │ └── resource.test.ts │ │ ├── activityBar │ │ │ ├── actionsControl.test.ts │ │ │ ├── activityBar.test.ts │ │ │ └── viewControl.test.ts │ │ ├── bottomBar │ │ │ ├── bottomBarPanel.test.ts │ │ │ ├── problemsView.test.ts │ │ │ └── views.test.ts │ │ ├── cli │ │ │ ├── order-1.test.ts │ │ │ ├── order-2.test.ts │ │ │ └── order-3.test.ts │ │ ├── debug │ │ │ └── debug.test.ts │ │ ├── dialog │ │ │ └── dialog.test.ts │ │ ├── editor │ │ │ ├── customEditor.test.ts │ │ │ ├── diffEditor.test.ts │ │ │ ├── editorView.test.ts │ │ │ ├── extensionEditor.test.ts │ │ │ ├── settingsEditor.test.ts │ │ │ └── textEditor.test.ts │ │ ├── menu │ │ │ ├── contextMenu.test.ts │ │ │ ├── macTitleBar.test.ts │ │ │ └── titleBar.test.ts │ │ ├── statusBar │ │ │ └── statusBar.test.ts │ │ ├── system │ │ │ └── clipboard.test.ts │ │ ├── webview │ │ │ ├── webView.test.ts │ │ │ └── webviewView.test.ts │ │ ├── workbench │ │ │ ├── input.test.ts │ │ │ ├── notifications.test.ts │ │ │ ├── open.test.ts │ │ │ └── workbench.test.ts │ │ └── xsideBar │ │ │ ├── customView.test.ts │ │ │ ├── scmView.test.ts │ │ │ ├── sideBarView.test.ts │ │ │ └── xtensionsView.test.ts │ └── treeView.ts │ └── tsconfig.json └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | .eslintrc.json -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 💡 Questions 4 | url: https://github.com/redhat-developer/vscode-extension-tester/discussions 5 | about: FAQ, Ideas, Q&A, ... 6 | - name: 📝 Documentation 7 | url: https://github.com/redhat-developer/vscode-extension-tester/wiki 8 | about: Documentation with examples of usage. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-requests.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature Request 2 | description: If something is missing or could be improved 3 | title: "[🚀 Request] " 4 | labels: [enhancement, new-issue] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thank you for taking the time to fill out this request report! 9 | - type: textarea 10 | id: description 11 | attributes: 12 | label: Describe the request 13 | description: What is the feature you are missing? or what would you like to improve? 14 | placeholder: | 15 | Please add as many details as possible. 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: example 20 | attributes: 21 | label: Usage 22 | description: Could you provide some example of usage? 23 | placeholder: | 24 | Please describe how the request is useful for you and vscode-extension-tester community. 25 | validations: 26 | required: true 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/tasks.yml: -------------------------------------------------------------------------------- 1 | name: 🔧 Task 2 | description: Simple changes, mainly maintenance manner 3 | title: "[🔧 Task] " 4 | labels: [task, new-issue] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: Thank you for taking the time to fill out this task description! 9 | - type: textarea 10 | id: description 11 | attributes: 12 | label: Describe the task 13 | description: What is missing? or what would you like to improve? or what needs to be changed? 14 | placeholder: | 15 | Please add as many details as possible. 16 | validations: 17 | required: true 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Before submitting your PR, please review the following checklist: 2 | 3 | - [ ] **CONSIDER** adding a new test if your PR resolves an issue. 4 | - [ ] **DO** keep pull requests small so they can be easily reviewed. 5 | - [ ] **DO** make sure tests pass. 6 | - [ ] **DO** make sure any public APIs changes are documented. 7 | - [ ] **DO** make sure not to introduce any compiler warnings. 8 | 9 | Before merging the PR: 10 | 11 | - [ ] **CHECK** continuous integration of `main` branch is green. 12 | - [ ] **CHECK** pull request check job is green. 13 | - [ ] **CHECK** all pull request questions/requests are resolved. 14 | - [ ] **WAIT** till PR is approved by at least 1 committer. 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | open-pull-requests-limit: 5 9 | labels: 10 | - "skip-changelog" 11 | - package-ecosystem: "npm" 12 | directory: "/" 13 | schedule: 14 | interval: "daily" 15 | groups: 16 | ESLint: 17 | patterns: ["*eslint*"] 18 | open-pull-requests-limit: 20 19 | versioning-strategy: increase 20 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - skip-changelog 5 | categories: 6 | - title: 🚫 Bugs 7 | labels: 8 | - bug 9 | - title: 🚀 Features 10 | labels: 11 | - enhancement 12 | - feature 13 | - title: 🔧 Tasks 14 | labels: 15 | - task 16 | - title: 🔎 Tests 17 | labels: 18 | - test 19 | - title: 📦 Dependencies 20 | labels: 21 | - dependencies 22 | - title: Other Changes 23 | labels: 24 | - "*" 25 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: 📊 Code Coverage 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | coverage: 16 | runs-on: ubuntu-latest 17 | 18 | env: 19 | CODE_TYPE: stable 20 | CODE_VERSION: max 21 | TEST_RESOURCES: test-resources 22 | 23 | steps: 24 | - name: 👷🏻 Checkout Repository 25 | uses: actions/checkout@v4 26 | 27 | - name: ⚙️ Setup NodeJS 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: 20 31 | cache: npm 32 | 33 | - name: 🔧 Install 34 | run: npm ci 35 | 36 | - name: 🔧 Build 37 | run: npm run build 38 | 39 | - name: 🔧 Install - Test Project 40 | run: npm install --workspace=extester-test 41 | 42 | - name: ⚙️ Allow unprivileged user namespace (ubuntu) 43 | run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 44 | 45 | - name: 📊 Run Tests with Coverage enabled 46 | # 'set +e' and 'exit 0' - that means the workflow will not fail even the test failures are present. The failing tests are not directive for the code coverage reports itself 47 | run: | 48 | set +e 49 | xvfb-run --auto-servernum --server-args='-screen 0 1920x1080x24' npm run test:coverage 50 | exit 0 51 | 52 | - name: 💾 Upload Coverage 53 | uses: actions/upload-artifact@v4 54 | if: always() 55 | with: 56 | name: coverage 57 | path: ${{ github.workspace }}/tests/**/coverage 58 | -------------------------------------------------------------------------------- /.github/workflows/insiders.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Insiders CI 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | push: 7 | branches: [insider] 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | test: 16 | uses: ./.github/workflows/template-main.yaml 17 | with: 18 | version: latest 19 | code_type: insider 20 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: 🏗️ Main CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | test: 16 | name: ${{ matrix.version }} 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | version: [min, 1.99.3, max] 21 | uses: ./.github/workflows/template-main.yaml 22 | with: 23 | version: ${{ matrix.version }} 24 | 25 | check: 26 | if: always() 27 | runs-on: ubuntu-latest 28 | name: 🚦 Status Check 29 | needs: [test] 30 | steps: 31 | - name: ℹ️ Test Matrix Result 32 | run: | 33 | echo result = ${{ needs.test.result }} 34 | - name: ✅ Status Check - success 35 | if: ${{ needs.test.result == 'success' }} 36 | run: | 37 | echo "All tests successfully completed!" 38 | exit 0 39 | - name: ❌ Status Check - failure 40 | if: ${{ needs.test.result != 'success' }} 41 | run: | 42 | echo "Status Check failed!" 43 | exit 1 44 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: 💎 NodeJS CI 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | workflow_dispatch: 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | test: 14 | name: ${{ matrix.node }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | node: [lts/*, latest] 19 | uses: ./.github/workflows/template-main.yaml 20 | with: 21 | version: max 22 | nodejs: ${{ matrix.node }} 23 | -------------------------------------------------------------------------------- /.github/workflows/publish-wiki.yml: -------------------------------------------------------------------------------- 1 | name: 📖 Publish wiki 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - docs/** 8 | - .github/workflows/publish-wiki.yml 9 | 10 | concurrency: 11 | group: publish-wiki 12 | cancel-in-progress: true 13 | 14 | permissions: 15 | contents: write 16 | 17 | jobs: 18 | publish-wiki: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: 🔧 Checkout 22 | uses: actions/checkout@v4 23 | - name: 📖 Build Wiki 24 | uses: Andrew-Chen-Wang/github-wiki-action@v4 25 | with: 26 | path: ./docs 27 | -------------------------------------------------------------------------------- /.github/workflows/stalebot.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/actions/stale 2 | name: 🗄️ Close Stale Issues and PRs 3 | 4 | on: 5 | schedule: 6 | - cron: "30 1 * * *" 7 | 8 | jobs: 9 | stale: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: 🗄️ Close Inactive 13 | uses: actions/stale@v9 14 | with: 15 | stale-issue-message: "This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days." 16 | stale-pr-message: "This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days." 17 | close-issue-message: "This issue was closed because it has been stalled for 5 days with no activity." 18 | exempt-issue-milestones: "BACKLOG,NEXT" 19 | exempt-all-assignees: true 20 | stale-issue-label: "no-issue-activity" 21 | stale-pr-label: "no-pr-activity" 22 | exempt-issue-labels: "enhancement,question,help-wanted,do-not-stale" 23 | exempt-pr-labels: "help-wanted,prio,do-not-stale" 24 | exempt-draft-pr: true 25 | -------------------------------------------------------------------------------- /.github/workflows/template-main.yaml: -------------------------------------------------------------------------------- 1 | name: 📄 Main CI - template 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | version: 7 | required: true 8 | type: string 9 | nodejs: 10 | required: false 11 | default: "20.x" 12 | type: string 13 | code_type: 14 | required: false 15 | default: "stable" 16 | type: string 17 | 18 | jobs: 19 | test: 20 | name: ${{ matrix.os }} 21 | runs-on: ${{ matrix.os }} 22 | strategy: 23 | matrix: 24 | os: [ubuntu-latest, macos-latest, windows-latest] 25 | fail-fast: false 26 | 27 | env: 28 | CODE_TYPE: ${{ inputs.code_type }} 29 | CODE_VERSION: ${{ inputs.version }} 30 | TEST_RESOURCES: test-resources 31 | 32 | steps: 33 | - name: 👷🏻 Checkout Repository 34 | uses: actions/checkout@v4 35 | 36 | - name: ⚙️ Setup NodeJS 37 | uses: actions/setup-node@v4 38 | with: 39 | node-version: ${{ inputs.nodejs }} 40 | cache: npm 41 | 42 | - name: 🔧 Install 43 | run: npm ci 44 | 45 | - name: 🔧 Build 46 | run: npm run build 47 | 48 | - name: ✨ Code Formatter - Prettier 49 | run: npx prettier . --check 50 | 51 | - name: 🔧 Install - Test Project 52 | run: npm install --workspace=extester-test 53 | 54 | - name: 🔍 Run Tests (macOS, windows) 55 | if: ${{ ! startsWith(matrix.os, 'ubuntu') }} 56 | run: npm test 57 | 58 | - name: ⚙️ Allow unprivileged user namespace (ubuntu) 59 | if: ${{ startsWith(matrix.os, 'ubuntu') }} 60 | run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 61 | 62 | - name: 🔍 Run Tests (linux) 63 | if: ${{ startsWith(matrix.os, 'ubuntu') }} 64 | run: xvfb-run --auto-servernum --server-args='-screen 0 1920x1080x24' npm test 65 | 66 | - name: 💾 Upload Screenshots 67 | uses: actions/upload-artifact@v4 68 | if: failure() && inputs.nodejs != 'lts/*' 69 | with: 70 | name: screenshots-${{ matrix.os }}-${{ inputs.version }}-node_${{ inputs.nodejs }} 71 | path: ${{ github.workspace }}/tests/**/screenshots/**/*.png 72 | 73 | - name: 💾 Upload Screenshots 74 | uses: actions/upload-artifact@v4 75 | if: failure() && inputs.nodejs == 'lts/*' 76 | with: 77 | name: screenshots-${{ matrix.os }}-${{ inputs.version }}-node_lts 78 | path: ${{ github.workspace }}/tests/**/screenshots/**/*.png 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | node_modules/ 3 | .npmrc 4 | tests/test-project/coverage/ 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | out/ 3 | resources/ 4 | test-resources/ 5 | test-extensions/ 6 | .test-extensions/ 7 | CODEOWNERS 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSameLine": false, 4 | "bracketSpacing": true, 5 | "endOfLine": "auto", 6 | "printWidth": 160, 7 | "semi": true, 8 | "singleQuote": true, 9 | "trailingComma": "all", 10 | "useTabs": true, 11 | "tabWidth": 4, 12 | "quoteProps": "as-needed", 13 | "overrides": [ 14 | { 15 | "files": ["*.yaml", "*.yml", "*.json", "*.md"], 16 | "options": { 17 | "useTabs": false, 18 | "tabWidth": 2, 19 | "singleQuote": false 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[javascript]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode" 4 | }, 5 | "[json]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "[jsonc]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "[typescript]": { 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | }, 14 | "editor.codeActionsOnSave": ["source.fixAll.eslint"], 15 | "editor.defaultFormatter": "esbenp.prettier-vscode", 16 | "editor.formatOnSave": true 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "path": "tests/test-project", 8 | "type": "npm", 9 | "script": "watch", 10 | "problemMatcher": "$tsc-watch", 11 | "isBackground": true, 12 | "presentation": { 13 | "reveal": "never" 14 | }, 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in 5 | # the repo. Unless a later match takes precedence, 6 | # @global-owner1 and @global-owner2 will be requested for 7 | # review when someone opens a pull request. 8 | * @redhat-developer/extester-maintainers 9 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. 38 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | We are supporting only the latest version of ExTester framework package. 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | latest | :white_check_mark: | 10 | 11 | ## Reporting a Vulnerability 12 | 13 | If you discover a vulnerability in the ExTester project, we encourage you to report it to us so that we can address it promptly. 14 | 15 | Here's how you can report a vulnerability: 16 | 17 | 1. Email the details of the vulnerability to . 18 | 2. Include as much information as possible about the vulnerability, including steps to reproduce if applicable. 19 | 3. Please do not disclose the vulnerability publicly until we have had a chance to investigate and respond. 20 | 21 | ### Expectations 22 | 23 | - We will acknowledge receipt of your vulnerability report within 3 business days. 24 | - We will strive to send regular updates on our investigation and planned fix. 25 | - If the vulnerability is accepted, we will work to address it in a timely manner, based on the severity and complexity. 26 | - If the vulnerability is declined, we will provide an explanation. 27 | 28 | Please note that the safety and security of our users are our top priorities, and we appreciate your cooperation and responsible disclosure. 29 | -------------------------------------------------------------------------------- /docs/ActionsControl.md: -------------------------------------------------------------------------------- 1 | ![actionControl](https://user-images.githubusercontent.com/4181232/56589258-27bb1900-65e5-11e9-9aef-7643f44697f4.png) 2 | 3 | #### Look up the ActionsControl by title 4 | 5 | Import and find the control through activity bar 6 | 7 | ```typescript 8 | import { ActivityBar, ActionsControl } from 'vscode-extension-tester'; 9 | ... 10 | // get actions control for 'Manage' 11 | const control: ActionsControl = new ActivityBar().getGlobalAction('Manage'); 12 | ``` 13 | 14 | #### Open action menu 15 | 16 | Click the action control to open its context menu 17 | 18 | ```typescript 19 | const menu = await control.openActionMenu(); 20 | ``` 21 | 22 | #### Get title 23 | 24 | Get the control's title 25 | 26 | ```typescript 27 | const title = control.getTitle(); 28 | ``` 29 | 30 | #### Open context menu 31 | 32 | Left click on the control to open the context menu (in this case has the same effect as openActionMenu) 33 | 34 | ```typescript 35 | const menu = await control.openContextMenu(); 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/ActivityBar.md: -------------------------------------------------------------------------------- 1 | ![activityBar](https://user-images.githubusercontent.com/4181232/56586855-c133fc00-65e0-11e9-9317-158d7fcedd43.png) 2 | 3 | #### Look up the Activity Bar 4 | 5 | Import and find the activity bar 6 | 7 | ```typescript 8 | import { ActivityBar } from 'vscode-extension-tester'; 9 | ... 10 | const activityBar = new ActivityBar(); 11 | ``` 12 | 13 | #### Get view controls 14 | 15 | Get handles for all view controls/buttons that operate the view containers 16 | 17 | ```typescript 18 | const controls = await activityBar.getViewControls(); 19 | ``` 20 | 21 | #### Get view control by title 22 | 23 | Find a view control/button in the activity bar by its title 24 | 25 | ```typescript 26 | // get Explorer view control 27 | const controls = await activityBar.getViewControl("Explorer"); 28 | ``` 29 | 30 | #### Get global actions 31 | 32 | Get handles for all global actions buttons on the bottom of the action bar 33 | 34 | ```typescript 35 | const actions = await activityBar.getGlobalActions(); 36 | ``` 37 | 38 | #### Get global action by title 39 | 40 | Find global actions button by title 41 | 42 | ```typescript 43 | const actions = await activityBar.getGlobalAction("Manage"); 44 | ``` 45 | 46 | #### Open context menu 47 | 48 | Left click on the activity bar to open the context menu 49 | 50 | ```typescript 51 | const menu = await activityBar.openContextMenu(); 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/BottomBarPanel.md: -------------------------------------------------------------------------------- 1 | ![bottomBar](https://user-images.githubusercontent.com/4181232/56640335-099bfa00-6673-11e9-957f-37c47db20ff4.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { BottomBarPanel } from 'vscode-extension-tester'; 7 | ... 8 | const bottomBar = new BottomBarPanel(); 9 | ``` 10 | 11 | #### Open/Close the panel 12 | 13 | ```typescript 14 | // open 15 | await bottomBar.toggle(true); 16 | // close 17 | await bottomBar.toggle(false); 18 | ``` 19 | 20 | #### Maximize/Restore the panel 21 | 22 | ```typescript 23 | await bottomBar.maximize(); 24 | await bottomBar.restore(); 25 | ``` 26 | 27 | #### Open specific view in the bottom panel 28 | 29 | ```typescript 30 | const problemsView = await bottomBar.openProblemsView(); 31 | const outputView = await bottomBar.openOutputView(); 32 | const debugConsoleView = await bottomBar.openDebugConsoleView(); 33 | const terminalView = await bottomBar.openTerminalView(); 34 | ``` 35 | 36 | #### Open custom panel 37 | 38 | ```typescript 39 | await bottomBar.openTab("name"); 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/ContentAssist.md: -------------------------------------------------------------------------------- 1 | ![codeAssist](https://user-images.githubusercontent.com/4181232/56645020-20474e80-667d-11e9-9ebb-4f84c45d9080.png) 2 | 3 | #### Open/Lookup 4 | 5 | ```typescript 6 | import { TextEditor, ContentAssist } from 'vscode-extension-tester'; 7 | ... 8 | const contentAssist = await new TextEditor().toggleContentAssist(true); 9 | ``` 10 | 11 | #### Get Items 12 | 13 | ```typescript 14 | // find if an item with given label is present 15 | const hasItem = await contentAssist.hasItem("Get"); 16 | // get an item by label 17 | const item = await contentAssist.getItem("Get"); 18 | // get all visible items 19 | const items = await contentAssist.getItems(); 20 | ``` 21 | 22 | #### Select an Item 23 | 24 | ```typescript 25 | await contentAssist.getItem("Get").click(); 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/ContextMenu.md: -------------------------------------------------------------------------------- 1 | ![contextMenu](https://user-images.githubusercontent.com/4181232/56651979-88e8f800-668a-11e9-97f6-0a3a7b582a8d.png) 2 | Page object for any context menu opened by left-clicking an element that has a context menu. Title bar items also produce context menus when clicked. 3 | 4 | #### Open/Lookup 5 | 6 | Typically, a context menu is opened by calling `openContextMenu` on elements that support it. For example: 7 | 8 | ```typescript 9 | import { ActivityBar, ContextMenu } from 'vscode-extension-tester'; 10 | ... 11 | const menu = await new ActivityBar().openContextMenu(); 12 | ``` 13 | 14 | #### Retrieve Items 15 | 16 | ```typescript 17 | // find if an item with title exists 18 | const exists = await menu.hasItem("Copy"); 19 | // get a handle for an item 20 | const item = await menu.getItem("Copy"); 21 | // get all displayed items 22 | const items = await menu.getItems(); 23 | ``` 24 | 25 | #### Select Item 26 | 27 | ```typescript 28 | // recursively select an item in nested submenus 29 | await menu.select("File", "Preferences", "Settings"); 30 | // select an item that has a child submenu 31 | const submenu = await menu.select("File", "Preferences"); 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/ContextMenuItem.md: -------------------------------------------------------------------------------- 1 | ![contextMenuItem](https://user-images.githubusercontent.com/4181232/56653068-26ddc200-668d-11e9-820e-dffb39000fea.png) 2 | 3 | #### Lookup 4 | 5 | One can retrieve an item from an open context menu, much like follows: 6 | 7 | ```typescript 8 | import { ActivityBar } from 'vscode-extension-tester'; 9 | ... 10 | const menu = await new ActivityBar().openContextMenu(); 11 | const item = await menu.getItem('References'); 12 | ``` 13 | 14 | #### Select/Click 15 | 16 | ```typescript 17 | // if item has no children 18 | await item.select(); 19 | // if there is a submenu under the item 20 | const submenu = await item.select(); 21 | ``` 22 | 23 | #### Get Parent Menu 24 | 25 | ```typescript 26 | const parentMenu = item.getParent(); 27 | ``` 28 | 29 | #### Get Label 30 | 31 | ```typescript 32 | const label = await item.getLabel(); 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/CustomEditor.md: -------------------------------------------------------------------------------- 1 | In case your extension contributes a `CustomEditor`/`CustomTextEditor`. Both are based on a webview, and the page object is a combination of a `Webview` and common editor functionality. 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { CustomEditor } from 'vscode-extension-tester' 7 | ... 8 | // make sure the editor is opened by now 9 | const editor = new CustomEditor(); 10 | ``` 11 | 12 | #### Webview 13 | 14 | The whole editor is serviced by a [[WebView]], we just need to get a reference to it. 15 | 16 | ```typescript 17 | const webview = editor.getWebView(); 18 | ``` 19 | 20 | #### Common Functionality 21 | 22 | Most editors share this: 23 | 24 | ```typescript 25 | // check if there are unsaved changes 26 | const dirty = await editor.isDirty(); 27 | // save 28 | await editor.save(); 29 | // open 'save as' prompt 30 | const prompt = await editor.saveAs(); 31 | // get title 32 | const title = await editor.getTitle(); 33 | // get the editor tab 34 | const tab = await editor.getTab(); 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/CustomTreeSection.md: -------------------------------------------------------------------------------- 1 | ![customTree](https://user-images.githubusercontent.com/4181232/65507524-6e7fa880-dece-11e9-93a5-e6ead75afc4e.png) 2 | 3 | The 'custom' tree section, usually contributed by extensions as TreeView. All The behavior is defined by the general [[ViewSection]] class. 4 | 5 | #### Lookup 6 | 7 | ```typescript 8 | import { SideBarView, CustomTreeSection } from 'vscode-extension-tester'; 9 | ... 10 | // Type is inferred automatically, the type cast here is used to be more explicit 11 | const section = await new SideBarView().getContent().getSection('servers') as CustomTreeSection; 12 | ``` 13 | 14 | #### Get Welcome Content 15 | 16 | Some sections may provide a welcome content when their tree is empty. 17 | 18 | ```typescript 19 | // find welcome content, return undefined if not present 20 | const welcome: WelcomeContentSection = await section.findWelcomeContent(); 21 | 22 | // get all the possible buttons and paragraphs in a list 23 | const contents = await welcome.getContents(); 24 | 25 | // get all buttons 26 | const btns = await welcome.getButtons(); 27 | 28 | // get specific button 29 | const btn = await welcome.getButton("title"); 30 | 31 | // get paragraphs as strings in a list 32 | const text = await welcome.getTextSections(); 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/DebugConsoleView.md: -------------------------------------------------------------------------------- 1 | Page object needs extending, currently minimal support. 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { BottomBarPanel, DebugConsoleView } from 'vscode-extension-tester'; 7 | ... 8 | const debugView = await new BottomBarPanel().openDebugConsoleView(); 9 | ``` 10 | 11 | #### Text Handling 12 | 13 | ```typescript 14 | // get all text as string 15 | const text = await debugView.getText(); 16 | // clear the text 17 | await debugView.clearText(); 18 | ``` 19 | 20 | #### Expressions 21 | 22 | ```typescript 23 | // type an expression 24 | await debugView.setExpression("expression"); 25 | // evaluate an existing expression 26 | await debugView.evaluateExpression(); 27 | // type and evaluate an expression 28 | await debugView.evaluateExpression("expression"); 29 | // get a handle for content assist 30 | const assist = await debugView.getContentAssist(); 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/DebugToolbar.md: -------------------------------------------------------------------------------- 1 | ![toolbar](https://user-images.githubusercontent.com/4181232/122540755-3bc5fe00-d029-11eb-8b74-77ee740acdad.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | // get a handle for existing toolbar (i.e. debug session needs to be in progress) 7 | const bar = await DebugToolbar.create(); 8 | ``` 9 | 10 | #### Buttons 11 | 12 | ```typescript 13 | // continue 14 | await bar.continue(); 15 | // pause 16 | await bar.pause(); 17 | // step over 18 | await bar.stepOver(); 19 | // step into 20 | await bar.stepInto(); 21 | // step out 22 | await bar.stepOut(); 23 | // restart 24 | await bar.restart(); 25 | // stop 26 | await bar.stop(); 27 | ``` 28 | 29 | #### Wait for code to pause again 30 | 31 | ```typescript 32 | await bar.waitForBreakPoint(); 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/Debugging-Tests.md: -------------------------------------------------------------------------------- 1 | Attaching a debugger from VS Code can be achieved with a launch configuration such as this one: 2 | 3 | ```json 4 | { 5 | "name": "Debug UI Tests", 6 | "type": "node", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/node_modules/.bin/extest", 9 | "args": ["setup-and-run", "${workspaceFolder}/out/ui-test/*.js", "--mocha_config", "${workspaceFolder}/src/ui-test/.mocharc-debug.js"], 10 | "console": "integratedTerminal", 11 | "internalConsoleOptions": "neverOpen" 12 | } 13 | ``` 14 | 15 | Sometimes Windows terminal has trouble interpreting the executable. If that happens, you can run the cli directly: 16 | 17 | ```json 18 | { 19 | "name": "Debug UI Tests", 20 | "type": "node", 21 | "request": "launch", 22 | "program": "${workspaceFolder}/node_modules/vscode-extension-tester/out/cli.js", 23 | "args": ["setup-and-run", "${workspaceFolder}/out/ui-test/*.js", "--mocha_config", "${workspaceFolder}/src/ui-test/.mocharc-debug.js"], 24 | "console": "integratedTerminal", 25 | "runtimeExecutable": "node", 26 | "internalConsoleOptions": "neverOpen" 27 | } 28 | ``` 29 | 30 | Change the `args` to fit your needs. Note the usage of `--mocha_config`, this is the supported way of globally changing test options. In this case, the important option is timeout (the default 2 second timeout is hardly enough to debug anything). 31 | 32 | We recommend using separate mocha configuration files for running, and debugging the tests, so you can globally control timeouts for each. Be aware that using per-test case timeout will override the global settings. 33 | 34 | To learn more about mocha configuration, check [[Mocha-Configuration]]. 35 | 36 | An example debugging setup can be found in [vscode-extension-tester-example](https://github.com/redhat-developer/vscode-extension-tester-example). 37 | -------------------------------------------------------------------------------- /docs/DefaultTreeSection.md: -------------------------------------------------------------------------------- 1 | ![section](https://user-images.githubusercontent.com/4181232/56656305-76c08700-6695-11e9-8630-e878ff478201.png) 2 | 3 | The 'default' tree section, as used in the explorer view. All The behavior is defined by the general [[ViewSection]] class. 4 | 5 | #### Lookup 6 | 7 | ```typescript 8 | import { SideBarView, DefaultTreeSection } from 'vscode-extension-tester'; 9 | ... 10 | // Type is inferred automatically, the type cast here is used to be more explicit 11 | const section = await new SideBarView().getContent().getSection('workspace') as DefaultTreeSection; 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/DiffEditor.md: -------------------------------------------------------------------------------- 1 | ![diff](https://user-images.githubusercontent.com/4181232/77437498-04947d00-6de5-11ea-9d8e-d41dd5440a78.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | // through editors view 7 | const diffEditor1 = await new EditorView().openEditor("editorTitle"); 8 | 9 | // directly 10 | const diffEditor2 = new DiffEditor(); 11 | ``` 12 | 13 | #### Working with the Contents 14 | 15 | Since diff editor is basicaly two text editors in one, the `DiffEditor` object gives you the ability to work with two editors: 16 | 17 | ```typescript 18 | // get the original editor 19 | const original = await diffEditor1.getOriginalEditor(); 20 | 21 | // get the modified editor 22 | const changed = await diffEditor1.getModifiedEditor(); 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/ExtensionEditorDetailsSections.md: -------------------------------------------------------------------------------- 1 | ExtensionEditorDetailsSections 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { ExtensionEditorDetailsSection } from 'vscode-extension-tester'; 7 | ... 8 | const extensionEditorDetails = new ExtensionEditorDetailsSection(); 9 | ``` 10 | 11 | You can get values using following functions: 12 | 13 | ```typescript 14 | await extensionEditorDetails.getCategories(); 15 | 16 | await extensionEditorDetails.getResources(); 17 | 18 | await extensionEditorDetails.getMoreInfo(); 19 | 20 | await extensionEditorDetails.getVersion(); // For VS Code 1.96+ 21 | 22 | await extensionEditorDetails.getMoreInfoItem("Identifier"); 23 | 24 | await extensionEditorDetails.getReadme(); // currently not supported (Blocked by https://github.com/redhat-developer/vscode-extension-tester/issues/1492) 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/ExtensionEditorView.md: -------------------------------------------------------------------------------- 1 | ExtensionEditorView 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { ExtensionEditorView } from 'vscode-extension-tester'; 7 | ... 8 | const extensionEditor = new ExtensionEditorView(); 9 | ``` 10 | 11 | #### Get values from opened extension 12 | 13 | You can get individual values using following functions: 14 | 15 | ```typescript 16 | await extensionEditor.getName(); 17 | 18 | await extensionEditor.getVersion(); // For VS Code 1.96+ it is required to use 'extensionEditorDetailsSection.getVersion()' instead 19 | 20 | await extensionEditor.getPublisher(); 21 | 22 | await extensionEditor.getDescription(); 23 | 24 | await extensionEditor.getCount(); 25 | ``` 26 | 27 | #### Manage tabs 28 | 29 | Tabs section can be managed by this editor as well. For work with 'Details' you can use ExtensionEditorDetailsSection. 30 | 31 | ```typescript 32 | await extensionEditor.getTabs(); 33 | 34 | await extensionEditor.switchToTab("tabname"); 35 | 36 | await extensionEditor.getActiveTab(); 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/ExtensionsViewSection.md: -------------------------------------------------------------------------------- 1 | ![extSection](https://user-images.githubusercontent.com/4181232/65507937-53f9ff00-decf-11e9-8fd8-093b350cf547.png) 2 | 3 | Section in the Extensions view. Unlike the other section types, extension sections behave differently. 4 | 5 | #### Lookup 6 | 7 | Get a section handle from an open side bar. 8 | 9 | ```typescript 10 | import { SideBarView, ExtensionsViewSection } from 'vscode-extension-tester'; 11 | ... 12 | // in this case the cast is required if you wish to use all the available functionality 13 | const section = await new SideBarView().getContent().getSection('enabled') as ExtensionsViewSection; 14 | ``` 15 | 16 | #### Finding Items 17 | 18 | Item lookup behaves in a completely different way to the tree sections. In this case it is based on the search bar on top of the view and as such is able to find items beyond the initial section. In this case you will need to manually clear the search bar in order to gain back access to the original section. 19 | 20 | ```typescript 21 | // get all visible items inside the section 22 | const items = await section.getVisibleItems(); 23 | 24 | // find an extension anywhere (including the marketplace) 25 | const item = await section.findItem("npm"); 26 | // clear the search bar so the original section reappears 27 | await section.clearSearch(); 28 | 29 | // find an extension in the installed section 30 | const item2 = await section.findItem("@installed java"); 31 | // clear the search bar so the original section reappears 32 | await section.clearSearch(); 33 | 34 | // open an item in the editor view 35 | await section.openItem("@installed java"); 36 | ``` 37 | 38 | #### ExtensionsViewItem 39 | 40 | ![extension](https://user-images.githubusercontent.com/4181232/65508733-24e48d00-ded1-11e9-9f53-1e47e8d79943.png) 41 | 42 | Item representing an extension in the extensions view. 43 | 44 | ##### Get information about the extension 45 | 46 | ```typescript 47 | // get title 48 | const title = await item.getTitle(); 49 | 50 | // get version 51 | const version = await item.getVersion(); 52 | 53 | // get author 54 | const author = await item.getAuthor(); 55 | 56 | // get description 57 | const description = await item.getDescription(); 58 | 59 | // find if it is installed 60 | const installed = await item.isInstalled(); 61 | ``` 62 | 63 | ##### Operations 64 | 65 | ```typescript 66 | // manage the item - open its context menu 67 | const menu = await item.manage(); 68 | 69 | // install the extension 70 | await item.install(); 71 | ``` 72 | -------------------------------------------------------------------------------- /docs/FindWidget.md: -------------------------------------------------------------------------------- 1 | ![find](https://user-images.githubusercontent.com/4181232/122541820-5fd60f00-d02a-11eb-99de-2c304bdc5dfe.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | // open the find widget from text editor 7 | const editor = new TextEditor(); 8 | const widget = await editor.openFindWidget(); 9 | ``` 10 | 11 | #### Search 12 | 13 | ```typescript 14 | // set search text 15 | await widget.setSearchText(); 16 | // get search text 17 | const text = await widget.getSearchText(); 18 | // find next 19 | await widget.nextMatch(); 20 | // find previous 21 | await widget.previousMatch(); 22 | // get result counts 23 | const counts = await widget.getResultCount(); 24 | const currentResultNumber = counts[0]; 25 | const totalCount = counts[1]; 26 | ``` 27 | 28 | #### Replace 29 | 30 | ```typescript 31 | // toggle replace on/off 32 | await widget.toggleReplace(true); // or false 33 | // set replace text 34 | await widget.setReplaceText(); 35 | // get replace text 36 | const text = await widget.getReplaceText(); 37 | // replace current match 38 | await widget.replace(); 39 | // replace all matches 40 | await widget.replaceAll(); 41 | ``` 42 | 43 | #### Switches 44 | 45 | ```typescript 46 | // switch 'Match Case' on/off 47 | await widget.toggleMatchCase(true / false); 48 | // switch 'Match Whole Word' on/off 49 | await widget.toggleMatchWholeWord(true / false); 50 | // switch 'Use Regular Expression' on/off 51 | await widget.toggleUseRegularExpression(true / false); 52 | // switch 'Preserve Case' on/off 53 | await widget.togglePreserveCase(true / false); 54 | ``` 55 | 56 | #### Close 57 | 58 | ```typescript 59 | await widget.close(); 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/Mocha-Configuration.md: -------------------------------------------------------------------------------- 1 | Since this framework is using Mocha programmatically, we lose certain ways to configure the test runner. We do however support using mocha configuration files, with roughly the same functionality as described in [mochajs documentation](https://mochajs.org/#configuring-mocha-nodejs). 2 | 3 | ### Configuration Options 4 | 5 | Extester supports three formats of mocha config files: 6 | 7 | - javascript file (.js) 8 | - json file (.json) 9 | - yaml file (.yml | .yaml) 10 | 11 | When using a JS file, make sure the options object is being exported as demonstrated [here](https://github.com/mochajs/mocha/blob/master/example/config/.mocharc.js). 12 | 13 | You can check out what options are supported in the [Mocha API documentation](https://mochajs.org/api/mocha). Any invalid mocha options declared will be ignored. 14 | 15 | ### Loading your Config File 16 | 17 | By default, the framework is going to scan the root of your project for files named `.mocharc` with one of the supported extensions (as does Mocha). If multiple files are present, the priority then is `JS (.mocharc.js) > JSON (.mocharc.json) > YAML (.mocharc.yml, .mocharc.yaml)`. 18 | 19 | Alternatively, you may use the `-m` flag with the command that runs your tests to specify a different path to your config file. For example 20 | 21 | ```sh 22 | extest setup-and-run -m 23 | ``` 24 | 25 | ### Type-safe Configuration Files 26 | 27 | If you wish to have your configuration type-checked, you can write the configuration in TypeScript using the `MochaOptions` interface. Make sure the .ts file is compiled, then use the `-m` flag to point to the compiled configuration. 28 | 29 | An example config.ts file might look like this: 30 | 31 | ```typescript 32 | import { MochaOptions } from "vscode-extension-tester"; 33 | 34 | const options: MochaOptions = { 35 | reporter: "spec", 36 | slow: 75, 37 | timeout: 2000, 38 | ui: "bdd", 39 | }; 40 | 41 | export default options; 42 | ``` 43 | 44 | ### ENV variables for Mocha options 45 | 46 | We are supporting only `MOCHA_GREP` and `MOCHA_INVERT` variables at the moment. It allows simpler overriding that options without need of modifying the Mocha config files. 47 | 48 | ```shell 49 | # Run the test case whose name is "ExtensionsView" 50 | MOCHA_GREP="ExtensionsView" npm run test 51 | 52 | # Run the test cases whose name is NOT "ExtensionsView" 53 | MOCHA_GREP="ExtensionsView" MOCHA_INVERT=true npm run test 54 | ``` 55 | -------------------------------------------------------------------------------- /docs/ModalDialog.md: -------------------------------------------------------------------------------- 1 | ![dialog](https://user-images.githubusercontent.com/4181232/108175328-ec1a0900-7100-11eb-97f5-e9c52ad19c78.png) 2 | 3 | Only available if you have the custom dialog style enabled, use `"window.dialogStyle": "custom"` in the settings to do so. 4 | 5 | #### Look up 6 | 7 | ```typescript 8 | const dialog = new ModalDialog(); 9 | ``` 10 | 11 | #### Get the contents 12 | 13 | ```typescript 14 | // get the message (the bold text) 15 | const message = await dialog.getMessage(); 16 | 17 | // get the details (the not so bold text) 18 | const details = await dialog.getDetails(); 19 | 20 | // get the button web elements 21 | const buttons = await dialog.getButtons(); 22 | ``` 23 | 24 | #### Push a button 25 | 26 | ```typescript 27 | // push button with a given title 28 | await dialog.pushButton("Save All"); 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/Notification.md: -------------------------------------------------------------------------------- 1 | ![notification](https://user-images.githubusercontent.com/4181232/56662617-b478dc00-66a4-11e9-9b1a-193efb96440b.png) 2 | 3 | #### Lookup 4 | 5 | To get notifications outside the notifications center, one should use a `Workbench` object: 6 | 7 | ```typescript 8 | import { Workbench } from 'vscode-extension-tester'; 9 | ... 10 | const notifications = await new Workbench().getNotifications(); 11 | const notification = notifications[0]; 12 | ``` 13 | 14 | #### Get Some Info 15 | 16 | ```typescript 17 | // get the message 18 | const message = await notification.getMessage(); 19 | // get the type (error/warning/info) 20 | const type = await notification.getType(); 21 | // get the source as string, if shown 22 | const source = await notification getSource(); 23 | // find if there is an active progress bar 24 | const hasProgress = await notification.hasProgress(); 25 | ``` 26 | 27 | #### Take Action 28 | 29 | ```typescript 30 | // dismiss the notification 31 | await notification.dismiss(); 32 | // get available actions (buttons) 33 | const actions = await notification.getActions(); 34 | // get an action's title (text) 35 | const title = actions[0].getTitle(); 36 | // take action (i.e. click a button with title) 37 | await notification.takeAction("Install All"); 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/NotificationsCenter.md: -------------------------------------------------------------------------------- 1 | ![center](https://user-images.githubusercontent.com/4181232/56663420-55b46200-66a6-11e9-8567-4dbde9a1ecb4.png) 2 | 3 | #### Lookup 4 | 5 | To open the notifications center, use either `Workbench` or `StatusBar` object: 6 | 7 | ```typescript 8 | import { Workbench, StatusBar, NotificationType } from 'vscode-extension-tester'; 9 | ... 10 | center = await new Workbench().openNotificationsCenter(); 11 | center1 = await new StatusBar().openNotificationsCenter(); 12 | ``` 13 | 14 | #### Get the Notifications 15 | 16 | ```typescript 17 | // get all notifications 18 | const notifications = await center.getNotifications(NotificationType.Any); 19 | // get info notifications 20 | const infos = await center.getNotifications(NotificationType.Info); 21 | ``` 22 | 23 | #### Clear and Close 24 | 25 | ```typescript 26 | // clear all notifications 27 | await center.clearAllNotifications(); 28 | // close the notifications center 29 | await center.close(); 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/OutputView.md: -------------------------------------------------------------------------------- 1 | ![output](https://user-images.githubusercontent.com/4181232/56642182-2c301200-6677-11e9-9ef3-70fdb914254c.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { BottomBarPanel, OutputView } from 'vscode-extension-tester'; 7 | ... 8 | const outputView = await new BottomBarPanel().openOutputView(); 9 | ``` 10 | 11 | #### Text Actions 12 | 13 | ```typescript 14 | // get all text 15 | const text = await outputView.getText(); 16 | // clear text 17 | await outputView.clearText(); 18 | ``` 19 | 20 | #### Channel Selection 21 | 22 | ```typescript 23 | // get names of all available channels 24 | const names = await outputView.getChannelNames(); 25 | // select a channel from the drop box by name 26 | await outputView.selectChannel("Git"); 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/Page-Object-APIs.md: -------------------------------------------------------------------------------- 1 | In order to keep everyone from having to go through the VS Code DOM, which is quite complicated, the framework provides page objects to work with parts of VS Code directly. 2 | 3 | See the individual page object pages below for quick usage guide. 4 | 5 | ##### Activity Bar 6 | 7 | - [[ActionsControl]] 8 | - [[ActivityBar]] 9 | - [[ViewControl]] 10 | 11 | ##### Bottom Bar 12 | 13 | - [[BottomBarPanel]] 14 | - [[DebugConsoleView]] 15 | - [[ProblemsView]] 16 | - [[OutputView]] 17 | - [[TerminalView]] 18 | 19 | ##### Dialogs 20 | 21 | - [[ModalDialog]] 22 | 23 | ##### Editor 24 | 25 | - [[ContentAssist]] 26 | - [[FindWidget]] 27 | - [[TextEditor]] 28 | - [[EditorView]] 29 | - [[SettingsEditor]] 30 | - [[Setting]] 31 | - [[WebView]] 32 | - [[DiffEditor]] 33 | - [[CustomEditor]] 34 | 35 | ##### Menu 36 | 37 | - [[ContextMenu]] 38 | - [[ContextMenuItem]] 39 | 40 | ##### Title Bar 41 | 42 | - [[TitleBar]] 43 | - [[TitleBarItem]] 44 | - [[WindowControls]] 45 | 46 | ##### Side Bar 47 | 48 | - [[SideBarView]] 49 | - [[ViewContent]] 50 | - [[ViewItem]] 51 | - [[ViewSection]] 52 | - [[DefaultTreeSection]] 53 | - [[CustomTreeSection]] 54 | - [[ExtensionsViewSection]] 55 | - [[ViewTitlePart]] 56 | - [[ScmView]] 57 | - [[DebugView]] 58 | 59 | ##### Status Bar 60 | 61 | - [[StatusBar]] 62 | 63 | ##### Workbench 64 | 65 | - [[Notification]] 66 | - [[NotificationsCenter]] 67 | - [[Workbench]] 68 | - [[Input]] 69 | - [[DebugToolbar]] 70 | -------------------------------------------------------------------------------- /docs/ProblemsView.md: -------------------------------------------------------------------------------- 1 | ![problems](https://user-images.githubusercontent.com/4181232/56641152-fe49ce00-6674-11e9-9a5d-096a61c0b835.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { BottomBarPanel, ProblemsView } from 'vscode-extension-tester'; 7 | ... 8 | const problemsView = await new BottomBarPanel().openProblemsView(); 9 | ``` 10 | 11 | #### Set a Filter 12 | 13 | Fill in a string into the filter box. 14 | 15 | ```typescript 16 | await problemsView.setFilter("**/filter/glob*"); 17 | ``` 18 | 19 | #### Collapse All Markers 20 | 21 | ```typescript 22 | await problemsView.collapseAll(); 23 | ``` 24 | 25 | #### Get Handles to All Markers 26 | 27 | ```typescript 28 | import { MarkerType } from 'vscode-extension-tester'; 29 | ... 30 | // get all markers regardless of type 31 | const markers = await problemsView.getAllVisibleMarkers(MarkerType.Any); 32 | // get all error markers 33 | const errors = await problemsView.getAllVisibleMarkers(MarkerType.Error); 34 | // get all warning markers 35 | const errors = await problemsView.getAllVisibleMarkers(MarkerType.Warning); 36 | // get all file markers 37 | const errors = await problemsView.getAllVisibleMarkers(MarkerType.File); 38 | ``` 39 | 40 | ### Marker 41 | 42 | Markers represent items displayed in the problems view. Each row corresponds to one Marker item. 43 | 44 | #### Retrieval 45 | 46 | ```typescript 47 | const markers = await problemsView.getAllVisibleMarkers(MarkerType.Any); 48 | const marker = markers[0]; 49 | ``` 50 | 51 | #### Actions 52 | 53 | ```typescript 54 | // get the marker type 55 | const type = await marker.getType(); 56 | // get the text of the marker row 57 | const text = await marker.getText(); 58 | // get the label of the marker 59 | const text = await marker.getLabel(); 60 | // expand the marker if available 61 | await marker.toggleExpand(true); 62 | // collapse 63 | await marker.toggleExpand(false); 64 | ``` 65 | -------------------------------------------------------------------------------- /docs/Setting.md: -------------------------------------------------------------------------------- 1 | ![setting](https://user-images.githubusercontent.com/4181232/62535346-76668900-b84b-11e9-8aa3-a07f25e1e37e.png) 2 | 3 | #### Lookup 4 | 5 | Settings can be located through a [[SettingsEditor]] object: 6 | 7 | ```typescript 8 | import { Workbench } from 'vscode-extension-tester'; 9 | ... 10 | // open the settings editor and get a handle on it 11 | const settingsEditor = await new Workbench().openSettings(); 12 | 13 | // look for a setting named 'Auto Save' under 'Editor' category 14 | const setting = await settingsEditor.findSetting('Auto Save', 'Files'); 15 | ``` 16 | 17 | #### Retrieve Information 18 | 19 | ```typescript 20 | // get the title 21 | const title = setting.getTitle(); 22 | 23 | // get the category 24 | const category = setting.getCategory(); 25 | 26 | // get the description 27 | const description = await setting.getDescription(); 28 | ``` 29 | 30 | #### Handling Values 31 | 32 | All setting types share the same functions to manipulate their values, however the value types and possible options vary between setting types. 33 | 34 | ```typescript 35 | // generic value retrieval 36 | const value = await setting.getValue(); 37 | 38 | // generic setting of a value 39 | await setting.setValue("off"); 40 | ``` 41 | 42 | ##### Setting Value Types 43 | 44 | Currently, there are four supported types of setting values: **text box**, **combo box**, **checkbox**, **link** and **array of strings**. 45 | 46 | - **Text box** allows putting in an arbitrary string value, though there might be value checks afterwards that are not handled by this class. 47 | - **Combo box** only allows inputs from its range of options. If you cast the setting to `ComboSetting`, you will be able to retrieve these options by calling the `getValues` method. 48 | - **Check box** only accepts boolean values, other values are ignored 49 | - **Link** does not have any value, `getValue` and `setValue` throw an error. Instead, casting the object to `LinkSetting` will allow you to call the `openLink` method, which will open settings.json file in a text editor. 50 | - **Array** settings are supported for type `string`. Each row of array is represented by `ArraySettingItem`. 51 | -------------------------------------------------------------------------------- /docs/SettingsEditor.md: -------------------------------------------------------------------------------- 1 | ![settings](https://user-images.githubusercontent.com/4181232/62535349-78304c80-b84b-11e9-80ae-25b587f11354.png) 2 | 3 | #### Lookup 4 | 5 | Settings editor can be opened through variety of ways, recommended way is using the [[Workbench]] class: 6 | 7 | ```typescript 8 | import { Workbench, SettingsEditor } from 'vscode-extension-tester' 9 | ... 10 | const settingsEditor = await new Workbench().openSettings(); 11 | ``` 12 | 13 | #### Find a Setting Item in the Editor 14 | 15 | Search for a setting with a given name and category, see more about the [[Setting]] object: 16 | 17 | ```typescript 18 | // look for a setting named 'Auto Save' under 'Editor' category 19 | const setting = await settingsEditor.findSetting("Auto Save", "Editor"); 20 | 21 | // find a setting in nested categories, e.g. 'Enable' in 'Files' > 'Simple Dialog' 22 | const setting1 = await settingsEditor.findSetting("Enable", "Files", "Simple Dialog"); 23 | ``` 24 | 25 | #### Switch Settings Perspectives 26 | 27 | VSCode has two perspectives for its settings: 'User' and 'Workspace'. If your VSCode instance loads from both user and workspace settings.json files, you will be able to switch the perspectives in the editor: 28 | 29 | ```typescript 30 | // switch to Workspace perspective 31 | await settingsEditor.switchToPerspective("Workspace"); 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/SideBarView.md: -------------------------------------------------------------------------------- 1 | ![sideBar](https://user-images.githubusercontent.com/4181232/56655128-327fb780-6692-11e9-83d0-d19ff1f8a836.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { ActivityBar, SideBarView } from "vscode-extension-tester"; 7 | // to look up the currently open view (if any is open) 8 | const view = new SideBarView(); 9 | // to open a specific view and look it up 10 | const control = await new ActivityBar().getViewControl("Explorer"); 11 | const view1 = await control.openView(); 12 | ``` 13 | 14 | #### Get Individual Parts 15 | 16 | ```typescript 17 | // to get the title part 18 | const titlePart = await view.getTitlePart(); 19 | // to get the content part 20 | const content = await view.getContent(); 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/StatusBar.md: -------------------------------------------------------------------------------- 1 | ![status](https://user-images.githubusercontent.com/4181232/56661682-91e5c380-66a2-11e9-859d-1974cb98006d.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { StatusBar } from 'vscode-extension-tester'; 7 | ... 8 | const statusbar = new StatusBar(); 9 | ``` 10 | 11 | #### Notifications Center 12 | 13 | ```typescript 14 | // open notifications center 15 | const center = await statusbar.openNotificationsCenter(); 16 | // close 17 | await statusbar.closeNotificationsCenter(); 18 | ``` 19 | 20 | #### Editor Status 21 | 22 | ```typescript 23 | // open language selection input 24 | await statusbar.openLanguageSelection(); 25 | // get current language as string 26 | const langString = await statusbar.getCurrentLanguage(); 27 | // open line ending selection input 28 | await statusbar.openLineEndingSelection(); 29 | // get current line ending as string 30 | const endingString = await statusbar.getCurrentLineEnding(); 31 | // open encoding selection input 32 | await statusbar.openEncodingSelection(); 33 | // get current encoding as string 34 | const encodingString = await statusbar.getCurrentEncoding(); 35 | // open indentation selection input 36 | await statusbar.openIndentationSelection(); 37 | // get current indentation as string 38 | const indentString = await statusbar.getCurrentIndentation(); 39 | // open line selection input 40 | await statusbar.openLineSelection(); 41 | // get current position as string (Ln X, Col Y) 42 | const posString = await statusbar.getCurrentPosition(); 43 | ``` 44 | 45 | #### Arbitrary Status Items 46 | 47 | ```typescript 48 | // find a status item by title 49 | const item = await statusbar.getItem("Select Encoding"); 50 | // get all status items as web elements 51 | const items = await statusbar.getItems(); 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/Taking Screenshots.md: -------------------------------------------------------------------------------- 1 | It is possible to take screenshots when testing Visual Studio Code extensions. 2 | Screenshot can be captured by calling: 3 | 4 | ```typescript 5 | VSBrowser.instance.takeScreenshot(basename: string) 6 | ``` 7 | 8 | Captured screenshots will be saved in _screenshots_ folder which can be found in a test storage folder (`$TMPDIR/test-resources` by default). 9 | File name will be generated from given basename in the following format: `${basename}.png`. 10 | 11 | #### Mocha integration 12 | 13 | Tester takes screenshots on all failed test cases. Screenshot name is 14 | determined by calling `this.currentTest.fullTitle()`. This feature does not apply to Mocha 15 | hooks by default. In order to capture screenshots on failed hooks, one 16 | must import vscode-extension-tester hook. 17 | 18 | ```typescript 19 | // Supported hooks: before, beforeEach, after and afterEach 20 | import { before } from "vscode-extension-tester"; 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/TerminalView.md: -------------------------------------------------------------------------------- 1 | ![term](https://user-images.githubusercontent.com/4181232/56642706-53d3aa00-6678-11e9-92b5-35c535ab39af.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { BottomBarPanel, TerminalView } from 'vscode-extension-tester'; 7 | ... 8 | const terminalView = await new BottomBarPanel().openTerminalView(); 9 | ``` 10 | 11 | #### Terminal Selection 12 | 13 | ```typescript 14 | // get names of all available terminals 15 | const names = await terminalView.getChannelNames(); 16 | // select a terminal from the drop box by name 17 | await terminalView.selectChannel("Git"); 18 | ``` 19 | 20 | #### Execute Commands 21 | 22 | ```typescript 23 | await terminalView.executeCommand("git status"); 24 | ``` 25 | 26 | #### Get Text 27 | 28 | Select all text and copy it to a variable. No formatting provided. 29 | 30 | - To allow copy text in terminal on macOS, you need to add specific setup in .vscode/settings.json `"terminal.integrated.copyOnSelection": true` 31 | 32 | ```typescript 33 | const text = await terminalView.getText(); 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/TitleBar.md: -------------------------------------------------------------------------------- 1 | ![titleBar](https://user-images.githubusercontent.com/4181232/56653724-986a4000-668e-11e9-9d5c-3d1998585f35.png) 2 | 3 | Page object for the title bar. Works only if the selected title bar type is 'custom'. Native title bar is not supported. 4 | 5 | #### Lookup 6 | 7 | ```typescript 8 | import { TitleBar } from 'vscode-extension-tester'; 9 | ... 10 | const titleBar = new TitleBar(); 11 | ``` 12 | 13 | #### Item Retrieval 14 | 15 | ```typescript 16 | // find if an item with title exists 17 | const exists = await titleBar.hasItem("File"); 18 | // get a handle for an item 19 | const item = await titleBar.getItem("File"); 20 | // get all displayed items 21 | const items = await titleBar.getItems(); 22 | ``` 23 | 24 | #### Get Displayed Title 25 | 26 | ```typescript 27 | const title = await titleBar.getTitle(); 28 | ``` 29 | 30 | #### Get Window Controls Handle 31 | 32 | ```typescript 33 | const controls = titleBar.getWindowControls(); 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/TitleBarItem.md: -------------------------------------------------------------------------------- 1 | ![titleBarItem](https://user-images.githubusercontent.com/4181232/56654111-918ffd00-668f-11e9-82a0-0e1cc2db2ad7.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { TitleBar } from "vscode-extension-tester"; 7 | 8 | // get an item from the title bar 9 | const item = await new TitleBar().getItem("File"); 10 | ``` 11 | 12 | #### Select the Item 13 | 14 | ```typescript 15 | const contextMenu = item.select(); 16 | ``` 17 | 18 | The rest of the functionality is exactly the same as other menu items, like [[ContextMenuItem]]. 19 | -------------------------------------------------------------------------------- /docs/ViewContent.md: -------------------------------------------------------------------------------- 1 | ![contentPart](https://user-images.githubusercontent.com/4181232/56655995-9c995c00-6694-11e9-963b-e7dd159c26d7.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { SideBarView } from 'vscode-extension-tester'; 7 | ... 8 | const contentPart = new SideBarView().getContent(); 9 | ``` 10 | 11 | #### Get Sections 12 | 13 | ```typescript 14 | // get a section by title, case insensitive 15 | const section = await contentPart.getSection("Open Editors"); 16 | // get all sections 17 | const sections = await contentPart.getSections(); 18 | ``` 19 | 20 | #### Progress Bar 21 | 22 | ```typescript 23 | // look if there is an active progress bar 24 | const hasProgress = await contentPart.hasProgress(); 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/ViewControl.md: -------------------------------------------------------------------------------- 1 | ![viewControl](https://user-images.githubusercontent.com/4181232/56588505-c47cb700-65e3-11e9-8636-8c35c1c1e648.png) 2 | 3 | #### Look up the ViewControl by title 4 | 5 | Import and find the control through activity bar 6 | 7 | ```typescript 8 | import { ActivityBar, ViewControl } from 'vscode-extension-tester'; 9 | ... 10 | // get view control for Explorer 11 | const control: ViewControl = new ActivityBar().getViewControl('Explorer'); 12 | ``` 13 | 14 | #### Open view 15 | 16 | Open the associated view if not already open and get a handler for it 17 | 18 | ```typescript 19 | const view = await control.openView(); 20 | ``` 21 | 22 | #### Close view 23 | 24 | Close the associated view if open 25 | 26 | ```typescript 27 | await control.closeView(); 28 | ``` 29 | 30 | #### Get title 31 | 32 | Get the control's/view's title 33 | 34 | ```typescript 35 | const title = control.getTitle(); 36 | ``` 37 | 38 | #### Open context menu 39 | 40 | Left click on the control to open the context menu 41 | 42 | ```typescript 43 | const menu = await control.openContextMenu(); 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/ViewItem.md: -------------------------------------------------------------------------------- 1 | ![item](https://user-images.githubusercontent.com/4181232/56657225-c7d17a80-6697-11e9-8690-5055d6737a7a.png) 2 | 3 | #### Lookup 4 | 5 | The best way to get an item reference is to use the `findItem` method from `ViewSection`. 6 | 7 | ```typescript 8 | const viewSection = ...; 9 | const item = await viewSection.findItem('package.json'); 10 | ``` 11 | 12 | #### Actions 13 | 14 | ```typescript 15 | // get item's label 16 | const label = item.getLabel(); 17 | // find if the item can be expanded 18 | const isExpandable = await item.isExpandable(); 19 | // try to expand the item and find if it has children 20 | const isParent = await item.hasChildren(); 21 | // find if item is expanded 22 | const isExpanded = await item.isExpanded(); 23 | // collapse the item if expanded 24 | await item.collapse(); 25 | // select the item and get its children if it ends up expanded, otherwise get an empty array 26 | const children = await item.select(); 27 | // get the tooltip if present 28 | const tooltip = await item.getTooltip(); 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/ViewSection.md: -------------------------------------------------------------------------------- 1 | ![section](https://user-images.githubusercontent.com/4181232/56656305-76c08700-6695-11e9-8630-e878ff478201.png) 2 | 3 | This is an abstract class for side bar view sections. Most behavior is defined here, but for specifics, check out the specific subtypes. 4 | 5 | #### Lookup 6 | 7 | Get a section handle from an open side bar. 8 | 9 | ```typescript 10 | import { SideBarView } from 'vscode-extension-tester'; 11 | ... 12 | const section = await new SideBarView().getContent().getSection('workspace'); 13 | ``` 14 | 15 | #### Section Manipulation 16 | 17 | ```typescript 18 | // get the section title 19 | const title = section.getTitle(); 20 | // collapse section if possible 21 | await section.collapse(timeout: ms); 22 | // expand if possible 23 | await section.expand(timeout: ms); 24 | // find if section is expanded 25 | const expanded = await section.isExpanded(); 26 | ``` 27 | 28 | #### Action Buttons 29 | 30 | Section header may also contain some action buttons. 31 | 32 | ```typescript 33 | // get an action button by label 34 | const action = (await section.getAction("New File")) as ViewPanelAction; 35 | // get all action buttons for the section 36 | const actions = await section.getActions(); 37 | // click an action button 38 | await action.click(); 39 | ``` 40 | 41 | ##### Action Buttons - Dropdown 42 | 43 | ![actionButtonDropdown](images/viewActions-dropdown.png) 44 | 45 | **Note:** Be aware that it is not supported on macOS. For more information see [Known Issues](https://github.com/redhat-developer/vscode-extension-tester/blob/main/KNOWN_ISSUES.md). 46 | 47 | ```typescript 48 | // find an view action button by title 49 | const action = (await view.getAction("Hello Who...")) as ViewPanelActionDropdown; 50 | // open the dropdown for that button 51 | const menu = await action.open(); 52 | // select an item from an opened context menu 53 | await menu.select("Hello a World"); 54 | ``` 55 | 56 | #### (Tree) Items Manipulation 57 | 58 | ```typescript 59 | // get all visible items, note that currently not shown on screen will not be retrieved 60 | const visibleItems = await section.getVisibleItems(); 61 | // find an item with a given label, involves scrolling to items currently not showing 62 | const item = await section.findItem("package.json"); 63 | // recursively navigate to an item and click it 64 | // if the item has children (./src/webdriver/components folder) 65 | const children = await section.openItem("src", "webdriver", "components"); 66 | // if the item is a leaf 67 | await section.openItem("src", "webdriver", "components", "AbstractElement.ts"); 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/ViewTitlePart.md: -------------------------------------------------------------------------------- 1 | ![titlePart](https://user-images.githubusercontent.com/4181232/56655603-935bbf80-6693-11e9-98f3-0e20a3256047.png) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { SideBarView } from 'vscode-extension-tester'; 7 | ... 8 | const titlePart = new SideBarView().getTitlePart(); 9 | ``` 10 | 11 | #### Get Title 12 | 13 | ```typescript 14 | const title = await titlePart.getTitle(); 15 | ``` 16 | 17 | #### ActionButtons 18 | 19 | Some views have action buttons in their title part. 20 | 21 | ```typescript 22 | // get action button by title 23 | const button = await titlePart.getActionButton("Clear"); 24 | // get all action buttons 25 | const buttons = await titlePart.getActionButtons(); 26 | // click a button 27 | await button.click(); 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/WebView.md: -------------------------------------------------------------------------------- 1 | ![webview sample](https://raw.githubusercontent.com/microsoft/vscode-extension-samples/master/webview-sample/demo.gif) 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { EditorView, WebView } from 'vscode-extension-tester'; 7 | ... 8 | // using EditorView 9 | const webview = new EditorView().openEditor('webview-title'); 10 | 11 | // using the constructor assuming the editor is opened 12 | const webview1 = new WebView(); 13 | ``` 14 | 15 | #### Switching Context 16 | 17 | In order to access the elements inside the web view frame, it is necessary to switch webdriver context into the frame. Analogically, to stop working with the web view, switching back is necessary. 18 | 19 | ```typescript 20 | // to switch inside the web view frame, with optional customizable timeout 21 | await webview.switchToFrame(5_000); 22 | 23 | // to switch back to the default window 24 | await webview.switchBack(); 25 | ``` 26 | 27 | #### Searching for Elements Inside a Web View 28 | 29 | Make sure when searching for and manipulating with elements inside (or outside) the web view that you have switched webdriver to the appropriate context. Also, be aware that referencing an element from the default window while switched to the web view (and vice versa) will throw a `StaleElementReference` error. 30 | 31 | ```typescript 32 | // first, switch inside the web view 33 | await webview.switchToFrame(); 34 | 35 | // look for desired elements 36 | const element = await webview.findWebElement(); 37 | const elements = await webview.findWebElements(); 38 | 39 | ... 40 | // after all web view manipulation is done, switch back to the default window 41 | await webview.switchBack(); 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/WebviewView.md: -------------------------------------------------------------------------------- 1 | Represents a extension-contributed view that's displayed in the bottom or side bar: 2 | 3 | ![A user-contributed panel in the bottom bar that displays a shopping list.](./images/webview-view-example.png) 4 | 5 | #### Lookup 6 | 7 | ```typescript 8 | import { WebviewView } from 'vscode-extension-tester'; 9 | ... 10 | // Focus the view using the command palette 11 | await new Workbench().executeCommand('My Panel: Focus on My Panel View View'); 12 | // Create the Webview View object to access the Webview View 13 | const webviewView = new WebviewView(); 14 | ``` 15 | 16 | #### Switching Context 17 | 18 | In order to access the elements inside the webview view frame, it is necessary to switch webdriver context into the frame. Analogically, to stop working with the webview view, switching back is necessary. 19 | 20 | ```typescript 21 | // to switch inside the webview view frame, with optional customizable timeout 22 | await webviewView.switchToFrame(5_000); 23 | 24 | // to switch back to the default window 25 | await webviewView.switchBack(); 26 | ``` 27 | 28 | #### Searching for Elements Inside a Webview View 29 | 30 | Make sure when searching for and manipulating with elements inside (or outside) the webview view that you have switched webdriver to the appropriate context. Also, be aware that referencing an element from the default window while switched to the webview view (and vice versa) will throw a `StaleElementReference` error. 31 | 32 | ```typescript 33 | // first, switch inside the webview view 34 | await webviewView.switchToFrame(); 35 | 36 | // look for desired elements 37 | const element = await webviewView.findWebElement(); 38 | const elements = await webviewView.findWebElements(); 39 | 40 | ... 41 | // after all webview view manipulation is done, switch back to the default window 42 | await webviewView.switchBack(); 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/WindowControls.md: -------------------------------------------------------------------------------- 1 | ![window controls](https://user-images.githubusercontent.com/4181232/56654449-622dc000-6690-11e9-9222-f8dc0dbd59dc.png) 2 | 3 | Controls to the whole window. Use at your own risk. 4 | 5 | #### Lookup 6 | 7 | ```typescript 8 | import { TitleBar } from 'vscode-extension-tester'; 9 | ... 10 | const controls = new TitleBar().getWindowControls(); 11 | ``` 12 | 13 | #### Manipulate Window 14 | 15 | ```typescript 16 | // minimize 17 | await controls.minimize(); 18 | // maximize 19 | await controls.maximize(); 20 | // restore 21 | await controls.restore(); 22 | // close... if you dare 23 | await controls.close(); 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/Workbench.md: -------------------------------------------------------------------------------- 1 | Workbench is the container for all the other elements. As such it mainly offers convenience methods to get handles for its subparts. It also retrieves handles for elements that are not accessible from a particular subpart. 2 | 3 | #### Lookup 4 | 5 | ```typescript 6 | import { Workbench } from 'vscode-extension-tester'; 7 | ... 8 | const workbench = new Workbench(); 9 | ``` 10 | 11 | #### Subparts Handles 12 | 13 | ```typescript 14 | // get title bar handle 15 | const titleBar = workbench.getTitleBar(); 16 | 17 | // get side bar handle 18 | const sideBar = workbench.getSideBar(); 19 | 20 | // get activity bar handle 21 | const activityBar = workbench.getActivityBar(); 22 | 23 | // get bottom bar handle 24 | const bottomBar = workbench.getBottomBar(); 25 | 26 | // get editor view handle 27 | const editorView = workbench.getEditorView(); 28 | 29 | // get notifications (outside notifications center) 30 | const notifications = workbench.getNotifications(); 31 | 32 | // open notifications center 33 | const center = workbench.openNotificationsCenter(); 34 | ``` 35 | 36 | #### Command Prompt 37 | 38 | You can also use `Workbench` to open the command prompt and execute commands. 39 | 40 | ```typescript 41 | // open command prompt, can then be handled as a QuickOpenBox 42 | const commandInput = await workbench.openCommandPrompt(); 43 | 44 | /* open command prompt and execute a command in it, the text does not need to be a perfect match 45 | uses VS Code's fuzzy search to find the best match */ 46 | await workbench.executeCommand("close workspace"); 47 | ``` 48 | 49 | #### Settings 50 | 51 | Opening the VS Code Settings editor is also available. 52 | 53 | ```typescript 54 | const settingsEditor = await workbench.openSettings(); 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/Writing-Simple-Tests.md: -------------------------------------------------------------------------------- 1 | ExTester is integrated with Mocha framework (as such requires Mocha 5.2+ to be present in your extension). To write a simple tests, one would write it just like a standard BDD Mocha test. 2 | 3 | This is what a really simple test case might look like. Note that here we are only using pure webdriver. To use the provided page objects, see the [[Page-Object-APIs]]. 4 | 5 | For an example project, check out the [vscode-extension-tester-example](https://github.com/redhat-developer/vscode-extension-tester-example) repository, where you can find detailed setup and usage instructions. 6 | 7 | ```typescript 8 | import { assert } from "chai"; 9 | // import the webdriver and the high level browser wrapper 10 | import { VSBrowser, WebDriver } from "vscode-extension-tester"; 11 | 12 | // Create a Mocha suite 13 | describe("My Test Suite", () => { 14 | let browser: VSBrowser; 15 | let driver: WebDriver; 16 | 17 | // initialize the browser and webdriver 18 | before(async () => { 19 | browser = VSBrowser.instance; 20 | driver = browser.driver; 21 | }); 22 | 23 | // test whatever we want using webdriver, here we are just checking the page title 24 | it("My Test Case", async () => { 25 | const title = await driver.getTitle(); 26 | assert.equal(title, "whatever"); 27 | }); 28 | }); 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/images/debugView-CallStack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/docs/images/debugView-CallStack.png -------------------------------------------------------------------------------- /docs/images/debugView-Variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/docs/images/debugView-Variables.png -------------------------------------------------------------------------------- /docs/images/debugView-WatchSection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/docs/images/debugView-WatchSection.png -------------------------------------------------------------------------------- /docs/images/editorActions-dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/docs/images/editorActions-dropdown.png -------------------------------------------------------------------------------- /docs/images/quickInputAction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/docs/images/quickInputAction.png -------------------------------------------------------------------------------- /docs/images/viewActions-dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/docs/images/viewActions-dropdown.png -------------------------------------------------------------------------------- /docs/images/webview-view-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/docs/images/webview-view-example.png -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | // eslint.config.js 2 | 3 | import { defineConfig } from 'eslint-define-config'; 4 | import ts from '@typescript-eslint/parser'; 5 | import tsEslint from '@typescript-eslint/eslint-plugin'; 6 | import stylisticEslint from '@stylistic/eslint-plugin'; 7 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; 8 | 9 | export default defineConfig([ 10 | { 11 | ignores: ['**/*.test.js'], 12 | }, 13 | eslintPluginPrettierRecommended, 14 | { 15 | files: ['**/*.ts', '**/*.tsx'], 16 | languageOptions: { 17 | parser: ts, 18 | parserOptions: { 19 | ecmaVersion: 2024, 20 | sourceType: 'module', 21 | project: './tsconfig.json', 22 | ecmaFeatures: { 23 | impliedStrict: true, 24 | }, 25 | }, 26 | globals: { 27 | // declare global variables here 28 | browser: 'readonly', 29 | es2024: true, 30 | mocha: 'readonly', 31 | }, 32 | }, 33 | plugins: { 34 | '@typescript-eslint': tsEslint, 35 | '@stylistic': stylisticEslint, 36 | }, 37 | rules: { 38 | '@typescript-eslint/no-var-requires': 'off', // allows require statements outside of imports 39 | '@typescript-eslint/no-floating-promises': 'warn', 40 | 'no-unused-expressions': 'off', 41 | '@typescript-eslint/no-unused-expressions': 'off', 42 | '@typescript-eslint/no-unused-vars': [ 43 | 'warn', 44 | { 45 | vars: 'all', 46 | args: 'after-used', 47 | ignoreRestSiblings: true, 48 | caughtErrors: 'none', // ignore unused variables in catch blocks 49 | }, 50 | ], 51 | '@typescript-eslint/no-namespace': 'off', 52 | '@typescript-eslint/no-explicit-any': 'off', 53 | '@typescript-eslint/no-this-alias': 'off', 54 | '@typescript-eslint/naming-convention': [ 55 | 'error', 56 | { 57 | selector: 'variable', 58 | format: ['camelCase', 'PascalCase', 'UPPER_CASE'], 59 | }, 60 | ], 61 | '@stylistic/semi': 'warn', 62 | curly: 'warn', 63 | eqeqeq: ['warn', 'always'], 64 | 'no-redeclare': 'warn', 65 | 'no-throw-literal': 'warn', 66 | 'prettier/prettier': ['warn'], 67 | }, 68 | }, 69 | ]); 70 | -------------------------------------------------------------------------------- /icons/extester-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/icons/extester-card.png -------------------------------------------------------------------------------- /icons/logo-text-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/icons/logo-text-bottom.png -------------------------------------------------------------------------------- /icons/logo-text-side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/icons/logo-text-side.png -------------------------------------------------------------------------------- /icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/icons/logo.png -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "version": "independent", 4 | "npmClient": "npm", 5 | "verbose": true, 6 | "command": { 7 | "version": { 8 | "message": "chore(release): Publish" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "name": "@redhat-developer/root", 4 | "description": "Lerna root of an ExTester monorepo.", 5 | "license": "Apache-2.0", 6 | "private": true, 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/redhat-developer/vscode-extension-tester.git" 10 | }, 11 | "scripts": { 12 | "version": "lerna version --no-private --no-push --signoff-git-commit", 13 | "publish": "lerna publish from-package --no-private", 14 | "prepublishOnly": "npm run build", 15 | "build": "lerna run build", 16 | "build:changed": "lerna run build --since main", 17 | "test": "npm run ui-test --workspace=extester-test", 18 | "test:coverage": "npm run ui-test:coverage --workspace=extester-test", 19 | "test:build": "npm run build:changed && npm install --workspace=extester-test && npm test" 20 | }, 21 | "workspaces": [ 22 | "packages/*", 23 | "tests/*" 24 | ], 25 | "devDependencies": { 26 | "@stylistic/eslint-plugin": "^4.4.1", 27 | "@types/chai": "^4.3.20", 28 | "@types/clone-deep": "^4.0.4", 29 | "@types/fs-extra": "^11.0.4", 30 | "@types/js-yaml": "^4.0.9", 31 | "@types/mocha": "^10.0.10", 32 | "@types/node": "^22.15.30", 33 | "@types/selenium-webdriver": "^4.1.28", 34 | "@types/targz": "^1.0.5", 35 | "@types/vscode": "^1.97.0", 36 | "@typescript-eslint/eslint-plugin": "^8.33.1", 37 | "@typescript-eslint/parser": "^8.32.1", 38 | "eslint": "^9.28.0", 39 | "eslint-config-prettier": "^10.1.5", 40 | "eslint-define-config": "^2.1.0", 41 | "eslint-plugin-prettier": "^5.4.1", 42 | "lerna": "^8.2.2", 43 | "prettier": "3.5.3", 44 | "rimraf": "^6.0.1", 45 | "typescript": "^5.8.3" 46 | }, 47 | "packageManager": "npm@10.9.2" 48 | } 49 | -------------------------------------------------------------------------------- /packages/extester/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-extension-tester", 3 | "version": "8.14.1", 4 | "description": "ExTester is a package that is designed to help you run UI tests for your Visual Studio Code extensions using selenium-webdriver.", 5 | "icon": "icons/logo.png", 6 | "main": "out/extester.js", 7 | "types": "out/extester.d.ts", 8 | "files": [ 9 | "out/**/*.js", 10 | "out/**/*.d.ts", 11 | "resources/*" 12 | ], 13 | "bin": { 14 | "extest": "out/cli.js" 15 | }, 16 | "scripts": { 17 | "prepack": "npm run build", 18 | "build": "npm run clean && npm run compile && chmod a+x ./out/cli.js", 19 | "compile": "tsc -p ./ && npm run lint", 20 | "lint": "eslint --fix --fix-type layout src", 21 | "clean": "rimraf out" 22 | }, 23 | "author": "Red Hat", 24 | "license": "Apache-2.0", 25 | "publishConfig": { 26 | "access": "public" 27 | }, 28 | "maintainers": [ 29 | { 30 | "name": "Dominik Jelinek", 31 | "email": "djelinek@redhat.com" 32 | } 33 | ], 34 | "bugs": { 35 | "url": "https://github.com/redhat-developer/vscode-extension-tester/issues" 36 | }, 37 | "homepage": "https://github.com/redhat-developer/vscode-extension-tester#readme", 38 | "repository": { 39 | "type": "git", 40 | "url": "https://github.com/redhat-developer/vscode-extension-tester.git", 41 | "directory": "packages/extester" 42 | }, 43 | "keywords": [ 44 | "webdriver", 45 | "selenium-webdriver", 46 | "selenium", 47 | "test", 48 | "vscode", 49 | "extension", 50 | "extester", 51 | "vscode-extension-tester", 52 | "ui-test" 53 | ], 54 | "supportedVersions": { 55 | "vscode-min": "1.98.2", 56 | "vscode-max": "1.100.3", 57 | "nodejs": "20" 58 | }, 59 | "dependencies": { 60 | "@redhat-developer/locators": "^1.12.1", 61 | "@redhat-developer/page-objects": "^1.12.1", 62 | "@types/selenium-webdriver": "^4.1.28", 63 | "@vscode/vsce": "^3.5.0", 64 | "c8": "^10.1.3", 65 | "commander": "^14.0.0", 66 | "compare-versions": "^6.1.1", 67 | "find-up": "7.0.0", 68 | "fs-extra": "^11.3.0", 69 | "glob": "^11.0.2", 70 | "got": "^14.4.7", 71 | "hpagent": "^1.2.0", 72 | "js-yaml": "^4.1.0", 73 | "sanitize-filename": "^1.6.3", 74 | "selenium-webdriver": "^4.33.0", 75 | "targz": "^1.0.1", 76 | "unzipper": "^0.12.3" 77 | }, 78 | "peerDependencies": { 79 | "mocha": ">=5.2.0", 80 | "typescript": ">=4.6.2" 81 | }, 82 | "devDependencies": { 83 | "@types/unzipper": "^0.10.11" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/extester/resources/state.vscdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/packages/extester/resources/state.vscdb -------------------------------------------------------------------------------- /packages/extester/src/util/unpack.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { PathLike } from 'fs-extra'; 19 | import unzip from 'unzipper'; 20 | import targz from 'targz'; 21 | import { exec } from 'child_process'; 22 | 23 | export class Unpack { 24 | static async unpack(input: PathLike, target: PathLike): Promise { 25 | return new Promise((resolve, reject) => { 26 | if (input.toString().endsWith('.tar.gz')) { 27 | targz.decompress( 28 | { 29 | src: input.toString(), 30 | dest: target.toString(), 31 | }, 32 | (err: string | Error | null | undefined) => { 33 | if (err) { 34 | const errWho = err instanceof Error ? err : new Error(err); 35 | reject(errWho); 36 | } else { 37 | resolve(); 38 | } 39 | }, 40 | ); 41 | } else if (input.toString().endsWith('.zip')) { 42 | if (process.platform === 'darwin' || process.platform === 'linux') { 43 | exec(`unzip -qo ${input.toString()}`, { cwd: target.toString() }, (err) => { 44 | if (err) { 45 | reject(new Error(err.message)); 46 | } else { 47 | resolve(); 48 | } 49 | }); 50 | } else { 51 | // WINDOWS, ... 52 | unzip.Open.file(`${input.toString()}`) 53 | .then((d: { extract: (arg0: { path: string; concurrency: number }) => any }) => 54 | d.extract({ path: `${target.toString()}`, concurrency: 5 }), 55 | ) 56 | .then((val: void | PromiseLike) => { 57 | resolve(val); 58 | }) 59 | .catch((err: { message: string | undefined }) => { 60 | reject(new Error(err.message)); 61 | }); 62 | } 63 | } else { 64 | reject(`Unsupported extension for '${input}'`); 65 | } 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/extester/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "out", 5 | "rootDir": "src", 6 | "lib": ["dom"] 7 | }, 8 | "include": ["src"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/locators/README.md: -------------------------------------------------------------------------------- 1 |

2 | ExTester for Visual Studio Code 3 |

4 | 5 |

Locators

6 | 7 |

8 | Pluggable Page Objects locators for an ExTester framework. 9 |

10 | -------------------------------------------------------------------------------- /packages/locators/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import * as path from 'path'; 19 | 20 | export function getLocatorsPath() { 21 | return path.join(__dirname, 'lib'); 22 | } 23 | -------------------------------------------------------------------------------- /packages/locators/lib/1.100.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | Input: { 23 | quickPickSelectAll: By.xpath(`.//div[@role='checkbox' and @aria-label='Toggle all checkboxes']`), 24 | }, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /packages/locators/lib/1.38.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | EditorView: { 24 | settingsEditor: By.xpath(`.//div[@data-editor-id='workbench.editor.settings2']`), 25 | webView: By.xpath(`.//div[@data-editor-id='WebviewEditor']`), 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /packages/locators/lib/1.39.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | BottomBarViews: { 24 | clearText: By.className('codicon-clear-all'), 25 | }, 26 | NotificationsCenter: { 27 | close: By.className('codicon-chevron-down'), 28 | clear: By.className('codicon-close-all'), 29 | }, 30 | Notification: { 31 | dismiss: By.className('codicon-close'), 32 | }, 33 | ScmView: { 34 | more: By.className('codicon-more'), 35 | }, 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /packages/locators/lib/1.40.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | NotificationsCenter: { 24 | close: By.className('codicon-close'), 25 | clear: By.className('codicon-clear-all'), 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /packages/locators/lib/1.41.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | ViewSection: { 24 | header: By.className('pane-header'), 25 | }, 26 | ScmView: { 27 | providerHeader: By.css(`div[class*='pane-header scm-provider']`), 28 | }, 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /packages/locators/lib/1.43.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | Input: { 24 | quickPickIndex: (index: number) => By.xpath(`.//div[@role='listitem' and @data-index='${index}']`), 25 | multiSelectIndex: (index: number) => By.xpath(`.//div[@role='listitem' and @data-index='${index}']`), 26 | }, 27 | NotificationsCenter: { 28 | close: By.className('codicon-chevron-down'), 29 | }, 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /packages/locators/lib/1.44.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | Input: { 24 | quickPickIndex: (index: number) => By.xpath(`.//div[@role='option' and @data-index='${index}']`), 25 | multiSelectIndex: (index: number) => By.xpath(`.//div[@role='option' and @data-index='${index}']`), 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /packages/locators/lib/1.45.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | EditorView: { 24 | tabSeparator: '', 25 | }, 26 | NotificationsCenter: { 27 | clear: By.className('codicon-notifications-clear-all'), 28 | close: By.className('codicon-notifications-hide'), 29 | }, 30 | Notification: { 31 | dismiss: By.className('codicon-notifications-clear'), 32 | }, 33 | ScmView: { 34 | more: By.className('codicon-toolbar-more'), 35 | }, 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /packages/locators/lib/1.46.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | CustomTreeItem: { 24 | constructor: (label: string) => By.xpath(`.//div[@role='listitem' and .//span[text()='${label}']]`), 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /packages/locators/lib/1.47.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | CustomTreeItem: { 24 | constructor: (label: string) => By.xpath(`.//div[@role='treeitem' and .//span[text()='${label}']]`), 25 | }, 26 | ScmView: { 27 | changes: By.xpath(`.//div[@role="treeitem" and .//div/text()="Changes"]`), 28 | stagedChanges: By.xpath(`.//div[@role="treeitem" and .//div/text()="Staged Changes"]`), 29 | providerTitle: By.className('name'), 30 | providerType: By.className('description'), 31 | }, 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /packages/locators/lib/1.49.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | TerminalView: { 24 | constructor: By.className('terminal-outer-container'), 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /packages/locators/lib/1.50.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | EditorView: { 24 | closeTab: By.className('codicon-close'), 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /packages/locators/lib/1.52.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | DefaultTreeItem: { 24 | tooltip: By.className('monaco-icon-label-container'), 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /packages/locators/lib/1.54.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | TerminalView: { 24 | newTerminal: By.xpath(`.//a[starts-with(@title, 'Create New Integrated Terminal')]`), 25 | killTerminal: By.xpath(`.//a[@title='Kill the Active Terminal Instance']`), 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /packages/locators/lib/1.56.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | EditorView: { 24 | webView: By.xpath(`.//div[starts-with(@id, 'webview-editor')]`), 25 | }, 26 | TerminalView: { 27 | newTerminal: By.xpath(`.//a[@title='New Terminal']`), 28 | }, 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /packages/locators/lib/1.57.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | EditorView: { 24 | settingsEditor: By.className('settings-editor'), 25 | }, 26 | TerminalView: { 27 | constructor: By.className('integrated-terminal'), 28 | }, 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /packages/locators/lib/1.59.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | FindWidget: { 23 | toggleReplace: By.xpath(`.//div[@title="Toggle Replace"]`), 24 | nextMatch: 'Next Match', 25 | previousMatch: 'Previous Match', 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /packages/locators/lib/1.60.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | TerminalView: { 23 | newCommand: 'terminal: create new terminal', 24 | }, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /packages/locators/lib/1.61.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | BottomBarPanel: { 23 | globalActions: By.className('global-actions'), 24 | }, 25 | DefaultTreeItem: { 26 | tooltip: By.className('monaco-icon-label'), 27 | }, 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/locators/lib/1.66.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | ContextMenu: { 23 | constructor: By.className('monaco-menu'), 24 | }, 25 | BottomBarPanel: { 26 | close: 'Close Panel', 27 | closeAction: By.className('codicon-panel-close'), 28 | }, 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /packages/locators/lib/1.70.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | BottomBarPanel: { 23 | action: (label: string) => By.xpath(`.//li[starts-with(@title, '${label}')]`), 24 | }, 25 | ViewSection: { 26 | buttonLabel: 'aria-label', 27 | }, 28 | ViewTitlePart: { 29 | action: By.className(`action-label`), 30 | actionConstructor: (title: string) => By.xpath(`.//a[@title='${title}']`), 31 | }, 32 | ScmView: { 33 | action: By.className('action-item menu-entry'), 34 | actionConstructor: (title: string) => By.xpath(`.//li[@title='${title}']`), 35 | }, 36 | EditorView: { 37 | attribute: 'aria-label', 38 | }, 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /packages/locators/lib/1.71.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { LocatorDiff } from '@redhat-developer/page-objects'; 19 | import { By } from 'selenium-webdriver'; 20 | 21 | export const diff: LocatorDiff = { 22 | locators: { 23 | EditorView: { 24 | attribute: 'aria-label', 25 | }, 26 | TreeItem: { 27 | actionTitle: 'aria-label', 28 | }, 29 | Input: { 30 | multiSelectIndex: (index: number) => By.xpath(`.//div[@role='checkbox' and @data-index='${index}']`), 31 | }, 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /packages/locators/lib/1.73.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | export const diff: LocatorDiff = { 20 | locators: { 21 | ProblemsView: { 22 | markersFilter: By.className('viewpane-filter'), 23 | }, 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/locators/lib/1.83.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | export const diff: LocatorDiff = { 20 | locators: { 21 | ViewSection: { 22 | actionConstructor: (label: string) => By.xpath(`.//a[contains(@class, 'action-label') and @role='button' and @aria-label='${label}']`), 23 | }, 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/locators/lib/1.84.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | export const diff: LocatorDiff = { 20 | locators: { 21 | BottomBarPanel: { 22 | tabContainer: By.className('composite-bar-container'), 23 | }, 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/locators/lib/1.85.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | export const diff: LocatorDiff = { 20 | locators: { 21 | Workbench: { 22 | notificationContainer: By.className('notifications-list-container'), 23 | }, 24 | ViewTitlePart: { 25 | actionConstructor: (title: string) => By.xpath(`.//a[@aria-label='${title}']`), 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /packages/locators/lib/1.87.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, fromText, LocatorDiff } from '@redhat-developer/page-objects'; 19 | export const diff: LocatorDiff = { 20 | locators: { 21 | BottomBarPanel: { 22 | close: 'Hide Panel', 23 | globalActions: By.className('global-actions'), 24 | action: (label: string) => By.xpath(`.//a[starts-with(@aria-label, '${label}')]`), 25 | }, 26 | SettingsEditor: { 27 | comboValue: 'value', 28 | }, 29 | FindWidget: { 30 | checkbox: (title: string) => By.xpath(`.//div[@role='checkbox' and starts-with(@aria-label, "${title}")]`), 31 | }, 32 | Notification: { 33 | buttonConstructor: (title: string) => By.xpath(`.//a[@role='button' and text()='${title}']`), 34 | actionLabel: { 35 | value: fromText(), 36 | }, 37 | }, 38 | ScmView: { 39 | action: By.className('action-label'), 40 | actionConstructor: (title: string) => By.xpath(`.//a[@aria-label='${title}']`), 41 | actionLabel: 'aria-label', 42 | }, 43 | ViewTitlePart: { 44 | actionLabel: 'aria-label', 45 | }, 46 | DefaultTreeItem: { 47 | labelAttribute: 'aria-label', 48 | }, 49 | Dialog: { 50 | buttonLabel: { 51 | value: fromText(), 52 | }, 53 | }, 54 | }, 55 | }; 56 | -------------------------------------------------------------------------------- /packages/locators/lib/1.88.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | FindWidget: { 23 | toggleReplace: By.xpath(`.//div[@aria-label="Toggle Replace"]`), 24 | button: (title: string) => By.xpath(`.//div[@role='button' and starts-with(@aria-label, "${title}")]`), 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /packages/locators/lib/1.90.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | WebviewView: { 23 | iframe: By.xpath(`//div[not(@data-parent-flow-to-element-id)]/iframe[@class='webview ready']`), 24 | }, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /packages/locators/lib/1.98.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | ScmView: { 23 | sourceControlSection: By.xpath(`.//div[@aria-label='Changes Section']`), 24 | }, 25 | ViewSection: { 26 | button: By.xpath(`.//a[contains(@class, 'action-label')]`), 27 | }, 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/locators/lib/1.99.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { By, LocatorDiff } from '@redhat-developer/page-objects'; 19 | 20 | export const diff: LocatorDiff = { 21 | locators: { 22 | ExtensionsViewItem: { 23 | author: By.className('publisher'), 24 | }, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /packages/locators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@redhat-developer/locators", 3 | "version": "1.12.1", 4 | "description": "Pluggable Page Objects locators for an ExTester framework.", 5 | "main": "out/index.js", 6 | "types": "out/index.d.ts", 7 | "files": [ 8 | "out/**/*.js", 9 | "out/**/*.d.ts" 10 | ], 11 | "author": "Red Hat", 12 | "license": "Apache-2.0", 13 | "publishConfig": { 14 | "access": "public" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/redhat-developer/vscode-extension-tester.git", 19 | "directory": "packages/locators" 20 | }, 21 | "keywords": [ 22 | "webdriver", 23 | "selenium-webdriver", 24 | "selenium", 25 | "test", 26 | "vscode", 27 | "extension", 28 | "extester", 29 | "vscode-extension-tester", 30 | "ui-test" 31 | ], 32 | "scripts": { 33 | "prepack": "npm run build", 34 | "build": "npm run clean && npm run compile", 35 | "compile": "tsc -p ./ && npm run lint", 36 | "lint": "eslint --fix --fix-type layout lib", 37 | "clean": "rimraf out" 38 | }, 39 | "peerDependencies": { 40 | "@redhat-developer/page-objects": ">=1.0.0", 41 | "selenium-webdriver": ">=4.6.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/locators/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "out", 5 | "rootDir": "." 6 | }, 7 | "include": ["index.ts", "lib"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/page-objects/README.md: -------------------------------------------------------------------------------- 1 |

2 | ExTester for Visual Studio Code 3 |

4 | 5 |

Page Objects

6 | 7 |

8 | Page Object API implementation for a VS Code editor used by ExTester framework.
📄 Documentation 9 |

10 | -------------------------------------------------------------------------------- /packages/page-objects/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@redhat-developer/page-objects", 3 | "version": "1.12.1", 4 | "description": "Page Object API implementation for a VS Code editor used by ExTester framework.", 5 | "main": "out/index.js", 6 | "types": "out/index.d.ts", 7 | "files": [ 8 | "out/**/*.js", 9 | "out/**/*.d.ts" 10 | ], 11 | "scripts": { 12 | "prepack": "npm run build", 13 | "build": "npm run clean && npm run compile", 14 | "compile": "tsc -p ./ && npm run lint", 15 | "lint": "eslint --fix --fix-type layout src", 16 | "clean": "rimraf out" 17 | }, 18 | "author": "Red Hat", 19 | "license": "Apache-2.0", 20 | "publishConfig": { 21 | "access": "public" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/redhat-developer/vscode-extension-tester.git", 26 | "directory": "packages/page-objects" 27 | }, 28 | "keywords": [ 29 | "webdriver", 30 | "selenium-webdriver", 31 | "selenium", 32 | "test", 33 | "vscode", 34 | "extension", 35 | "extester", 36 | "vscode-extension-tester", 37 | "ui-test" 38 | ], 39 | "dependencies": { 40 | "clipboardy": "^4.0.0", 41 | "clone-deep": "^4.0.1", 42 | "compare-versions": "^6.1.1", 43 | "fs-extra": "^11.3.0", 44 | "type-fest": "^4.41.0" 45 | }, 46 | "peerDependencies": { 47 | "selenium-webdriver": ">=4.6.1", 48 | "typescript": ">=4.6.2" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/ActionButtonElementDropdown.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { ContextMenu } from './menu/ContextMenu'; 19 | import { AbstractElement } from './AbstractElement'; 20 | import { By } from 'selenium-webdriver'; 21 | 22 | export abstract class ActionButtonElementDropdown extends AbstractElement { 23 | async open(): Promise { 24 | await this.click(); 25 | const shadowRootHost = await this.enclosingItem.findElements(ActionButtonElementDropdown.locators.ContextMenu.shadowRootHost); 26 | const actions = this.getDriver().actions(); 27 | await actions.clear(); 28 | 29 | if (shadowRootHost.length > 0) { 30 | if ((await this.getAttribute('aria-expanded')) !== 'true') { 31 | await this.click(); 32 | } 33 | const shadowRoot = await shadowRootHost[0].getShadowRoot(); 34 | return new ContextMenu(await shadowRoot.findElement(By.className('monaco-menu-container'))).wait(); 35 | } else { 36 | const workbench = await this.getDriver().findElement(ActionButtonElementDropdown.locators.Workbench.constructor); 37 | return new ContextMenu(workbench).wait(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/ElementWithContextMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { AbstractElement } from './AbstractElement'; 19 | import { ContextMenu } from '..'; 20 | import { until, error } from 'selenium-webdriver'; 21 | 22 | /** 23 | * Abstract element that has a context menu 24 | */ 25 | export abstract class ElementWithContextMenu extends AbstractElement { 26 | /** 27 | * Open context menu on the element 28 | */ 29 | async openContextMenu(): Promise { 30 | const workbench = await this.getDriver().findElement(ElementWithContextMenu.locators.Workbench.constructor); 31 | const menus = await workbench.findElements(ElementWithContextMenu.locators.ContextMenu.contextView); 32 | 33 | if (menus.length < 1) { 34 | await this.getDriver().actions().contextClick(this).perform(); 35 | await this.getDriver().wait(until.elementLocated(ElementWithContextMenu.locators.ContextMenu.contextView), 2000); 36 | return new ContextMenu(workbench).wait(); 37 | } else if ((await workbench.findElements(ElementWithContextMenu.locators.ContextMenu.viewBlock)).length > 0) { 38 | await this.getDriver().actions().contextClick(this).perform(); 39 | try { 40 | await this.getDriver().wait(until.elementIsNotVisible(this), 1000); 41 | } catch (err) { 42 | if (!(err instanceof error.StaleElementReferenceError)) { 43 | throw err; 44 | } 45 | } 46 | } 47 | await this.getDriver().actions().contextClick(this).perform(); 48 | 49 | return new ContextMenu(workbench).wait(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/activityBar/ActionsControl.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { WebElement } from 'selenium-webdriver'; 19 | import { ActivityBar, ContextMenu } from '../..'; 20 | import { ElementWithContextMenu } from '../ElementWithContextMenu'; 21 | 22 | /** 23 | * Page object representing the global action controls on the bottom of the action bar 24 | */ 25 | export class ActionsControl extends ElementWithContextMenu { 26 | constructor(element: WebElement, bar: ActivityBar) { 27 | super(element, bar); 28 | } 29 | 30 | /** 31 | * Open the context menu bound to this global action 32 | * @returns Promise resolving to ContextMenu object representing the action's menu 33 | */ 34 | async openActionMenu(): Promise { 35 | return await this.openContextMenu(); 36 | } 37 | 38 | /** 39 | * Returns the title of the associated action 40 | */ 41 | async getTitle(): Promise { 42 | return await this.getAttribute('aria-label'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/bottomBar/WebviewView.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /* eslint-disable no-redeclare */ 19 | import { Locator, WebElement } from 'selenium-webdriver'; 20 | import { AbstractElement } from '../AbstractElement'; 21 | import WebviewMixin from '../WebviewMixin'; 22 | import { findBestContainingElement } from '../../locators/locators'; 23 | 24 | /** 25 | * Page object representing a user-contributed panel implemented using a Webview. 26 | */ 27 | class WebviewViewBase extends AbstractElement { 28 | constructor(base: Locator | WebElement = WebviewViewBase.locators.Workbench.constructor, enclosingItem?: WebElement | Locator) { 29 | super(base, enclosingItem); 30 | } 31 | 32 | async getViewToSwitchTo(): Promise { 33 | const frames = await this.getDriver().findElements(WebviewViewBase.locators.WebView.iframe); 34 | return findBestContainingElement(await this.getRect(), frames); 35 | } 36 | } 37 | 38 | export const WebviewView = WebviewMixin(WebviewViewBase); 39 | export type WebviewView = InstanceType; 40 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/editor/Breakpoint.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { until, WebElement } from 'selenium-webdriver'; 19 | import { AbstractElement } from '../AbstractElement'; 20 | 21 | export class Breakpoint extends AbstractElement { 22 | constructor( 23 | breakpoint: WebElement, 24 | private lineElement: WebElement, 25 | ) { 26 | super(breakpoint, lineElement); 27 | } 28 | 29 | async isEnabled(): Promise { 30 | return await Breakpoint.locators.TextEditor.breakpoint.properties.enabled(this); 31 | } 32 | 33 | async isPaused(): Promise { 34 | return await Breakpoint.locators.TextEditor.breakpoint.properties.paused(this); 35 | } 36 | 37 | /** 38 | * Return line number of the breakpoint. 39 | * @returns number indicating line where breakpoint is set 40 | */ 41 | async getLineNumber(): Promise { 42 | const breakpointLocators = Breakpoint.locators.TextEditor.breakpoint; 43 | const line = await this.lineElement.findElement(breakpointLocators.properties.line.selector); 44 | const lineNumber = await breakpointLocators.properties.line.number(line); 45 | return lineNumber; 46 | } 47 | 48 | /** 49 | * Remove breakpoint. 50 | * @param timeout time in ms when operation is considered to be unsuccessful 51 | */ 52 | async remove(timeout: number = 5000): Promise { 53 | await this.click(); 54 | await this.getDriver().wait(until.stalenessOf(this), timeout); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/editor/CustomEditor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { Key } from 'selenium-webdriver'; 19 | import { Editor, InputBox, WebView } from '../..'; 20 | 21 | /** 22 | * Page object for custom editors 23 | */ 24 | export class CustomEditor extends Editor { 25 | /** 26 | * Get the WebView object contained in the editor 27 | * @returns WebView page object 28 | */ 29 | getWebView(): WebView { 30 | return new WebView(); 31 | } 32 | 33 | /** 34 | * Check if the editor has unsaved changes 35 | * @returns Promise resolving to true if there are unsaved changes, false otherwise 36 | */ 37 | async isDirty(): Promise { 38 | const tab = await this.getTab(); 39 | const klass = await tab.getAttribute('class'); 40 | return klass.includes('dirty'); 41 | } 42 | 43 | /** 44 | * Save the editor 45 | */ 46 | async save(): Promise { 47 | const tab = await this.getTab(); 48 | await tab.sendKeys(Key.chord(CustomEditor.ctlKey, 's')); 49 | } 50 | 51 | /** 52 | * Open the Save as prompt 53 | * 54 | * @returns InputBox serving as a simple file dialog 55 | */ 56 | async saveAs(): Promise { 57 | const tab = await this.getTab(); 58 | await tab.sendKeys(Key.chord(CustomEditor.ctlKey, Key.SHIFT, 's')); 59 | return await InputBox.create(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/editor/DiffEditor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { Editor } from './Editor'; 19 | import { TextEditor } from './TextEditor'; 20 | import { EditorView } from './EditorView'; 21 | 22 | /** 23 | * Page object representing a diff editor 24 | */ 25 | export class DiffEditor extends Editor { 26 | /** 27 | * Gets the text editor corresponding to the originalside. 28 | * (The left side of the diff editor) 29 | * @returns Promise resolving to TextEditor object 30 | */ 31 | async getOriginalEditor(): Promise { 32 | const element = await this.getEnclosingElement().findElement(DiffEditor.locators.DiffEditor.originalEditor); 33 | return new TextEditor(new EditorView(), element); 34 | } 35 | 36 | /** 37 | * Gets the text editor corresponding to the modified side. 38 | * (The right side of the diff editor) 39 | * @returns Promise resolving to TextEditor object 40 | */ 41 | async getModifiedEditor(): Promise { 42 | const element = await this.getEnclosingElement().findElement(DiffEditor.locators.DiffEditor.modifiedEditor); 43 | return new TextEditor(new EditorView(), element); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/editor/Editor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { ElementWithContextMenu } from '../ElementWithContextMenu'; 19 | import { EditorTab, EditorView, EditorGroup } from '../..'; 20 | import { WebElement, Locator } from 'selenium-webdriver'; 21 | 22 | /** 23 | * Abstract representation of an editor tab 24 | */ 25 | export abstract class Editor extends ElementWithContextMenu { 26 | constructor(view: EditorView | EditorGroup = new EditorView(), base: Locator | WebElement = Editor.locators.Editor.constructor) { 27 | super(base, view); 28 | } 29 | 30 | /** 31 | * Get title/name of the open editor 32 | */ 33 | async getTitle(): Promise { 34 | const tab = await this.getTab(); 35 | return await tab.getTitle(); 36 | } 37 | 38 | /** 39 | * Get the corresponding editor tab 40 | */ 41 | async getTab(): Promise { 42 | const element = this.enclosingItem as EditorView | EditorGroup; 43 | return (await element.getActiveTab()) as EditorTab; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/editor/EditorAction.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { ActionButtonElementDropdown } from '../ActionButtonElementDropdown'; 19 | 20 | /** 21 | * Base class for editor actions that provides a common method to get the title. 22 | */ 23 | abstract class BaseEditorAction extends ActionButtonElementDropdown { 24 | /** 25 | * Get text description of the action. 26 | */ 27 | async getTitle(): Promise { 28 | return await this.getAttribute(BaseEditorAction.locators.EditorView.attribute); 29 | } 30 | } 31 | 32 | export class EditorAction extends BaseEditorAction {} 33 | 34 | export class EditorActionDropdown extends BaseEditorAction {} 35 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/editor/WebView.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /* eslint-disable no-redeclare */ 19 | import { WebElement } from 'selenium-webdriver'; 20 | import WebviewMixin from '../WebviewMixin'; 21 | import { Editor } from './Editor'; 22 | import { findBestContainingElement } from '../../locators/locators'; 23 | 24 | /** 25 | * Page object representing an open editor containing a web view 26 | */ 27 | class WebViewBase extends Editor { 28 | async getViewToSwitchTo(): Promise { 29 | const frames = await this.getDriver().findElements(WebViewBase.locators.WebView.iframe); 30 | return findBestContainingElement(await this.getRect(), frames); 31 | } 32 | } 33 | 34 | export const WebView = WebviewMixin(WebViewBase); 35 | export type WebView = InstanceType; 36 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/menu/MacTitleBar.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { execSync } from 'child_process'; 19 | 20 | /** 21 | * Handler object for macOS based title bar 22 | */ 23 | export class MacTitleBar { 24 | /** 25 | * Select an item from the mac menu bar by its path, 26 | * does not actually visibly open the menus. 27 | * 28 | * @param items varargs path to the given menu item 29 | * each argument serves as a part of the path in order, 30 | * 31 | * e.g. ('File', 'Save') will select the 'Save' item from 32 | * the 'File' submenu 33 | */ 34 | static select(...items: string[]): void { 35 | let menuCounter = 0; 36 | const commands = [`tell application "System Events"`, `tell process "Code"`, `tell menu bar item "${items[0]}" of menu bar 1`]; 37 | for (let i = 1; i < items.length - 1; i++) { 38 | commands.push(`tell menu item "${items[i]}" of menu 1`); 39 | ++menuCounter; 40 | } 41 | if (items.length > 1) { 42 | commands.push(`click menu item "${items[items.length - 1]}" of menu 1`); 43 | } 44 | for (let i = 0; i < menuCounter + 3; i++) { 45 | commands.push(`end tell`); 46 | } 47 | const command = `osascript -e '${commands.join('\n')}'`; 48 | execSync(command); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/menu/MenuItem.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { AbstractElement } from '../AbstractElement'; 19 | import { Menu } from './Menu'; 20 | 21 | /** 22 | * Abstract element representing a menu item 23 | */ 24 | export abstract class MenuItem extends AbstractElement { 25 | protected parent!: Menu; 26 | protected label!: string; 27 | 28 | /** 29 | * Use the given menu item: Opens the submenu if the item has children, 30 | * otherwise simply click the item. 31 | * 32 | * @returns Menu object representing the submenu if the item has children, void otherwise. 33 | */ 34 | async select(): Promise { 35 | await this.click(); 36 | await new Promise((res) => setTimeout(res, 500)); 37 | return undefined; 38 | } 39 | 40 | /** 41 | * Return the Menu object representing the menu this item belongs to 42 | */ 43 | getParent(): Menu { 44 | return this.parent; 45 | } 46 | 47 | /** 48 | * Returns the label of the menu item 49 | */ 50 | getLabel(): string | Promise { 51 | return this.label; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/SideBarView.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { AbstractElement } from '../AbstractElement'; 19 | import { ViewTitlePart, ViewContent } from '../..'; 20 | 21 | /** 22 | * Page object for the side bar view 23 | */ 24 | export class SideBarView extends AbstractElement { 25 | constructor() { 26 | super(SideBarView.locators.SideBarView.constructor, SideBarView.locators.Workbench.constructor); 27 | } 28 | 29 | /** 30 | * Get the top part of the open view (contains title and possibly some buttons) 31 | * @returns ViewTitlePart object 32 | */ 33 | getTitlePart(): ViewTitlePart { 34 | return new ViewTitlePart(this); 35 | } 36 | 37 | /** 38 | * Get the content part of the open view 39 | * @returns ViewContent object 40 | */ 41 | getContent(): ViewContent { 42 | return new ViewContent(this); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/custom/CustomTreeItem.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { TreeItem } from '../../ViewItem'; 19 | import { TreeSection } from '../TreeSection'; 20 | import { WebElement } from 'selenium-webdriver'; 21 | 22 | /** 23 | * View item in a custom-made content section (e.g. an extension tree view) 24 | */ 25 | export class CustomTreeItem extends TreeItem { 26 | constructor(element: WebElement, viewPart: TreeSection) { 27 | super(element, viewPart); 28 | } 29 | 30 | async getLabel(): Promise { 31 | return await this.findElement(CustomTreeItem.locators.CustomTreeSection.itemLabel).getText(); 32 | } 33 | 34 | async getTooltip(): Promise { 35 | return await this.getAttribute(CustomTreeItem.locators.CustomTreeItem.tooltipAttribute); 36 | } 37 | 38 | async getDescription(): Promise { 39 | return await this.findElement(CustomTreeItem.locators.CustomTreeItem.description).getText(); 40 | } 41 | 42 | async isExpanded(): Promise { 43 | const attr = await this.getAttribute(CustomTreeItem.locators.CustomTreeItem.expandedAttr); 44 | return attr === CustomTreeItem.locators.CustomTreeItem.expandedValue; 45 | } 46 | 47 | async getChildren(): Promise { 48 | const rows = await this.getChildItems(CustomTreeItem.locators.DefaultTreeSection.itemRow); 49 | const items = await Promise.all(rows.map(async (row) => new CustomTreeItem(row, this.enclosingItem as TreeSection).wait())); 50 | return items; 51 | } 52 | 53 | async isExpandable(): Promise { 54 | const attr = await this.getAttribute(CustomTreeItem.locators.CustomTreeItem.expandedAttr); 55 | return attr !== null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/debug/CallStackItem.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { WebElement } from 'selenium-webdriver'; 19 | import { TreeSection } from '../TreeSection'; 20 | import { CustomTreeItem } from '../custom/CustomTreeItem'; 21 | 22 | export class CallStackItem extends CustomTreeItem { 23 | constructor(element: WebElement, viewPart: TreeSection) { 24 | super(element, viewPart); 25 | } 26 | 27 | /** 28 | * Get label of the Call Stack item. 29 | * @returns a promise resolving to Call Stack item label string 30 | */ 31 | async getLabel(): Promise { 32 | const name = await this.findElement(CallStackItem.locators.CallStackItem.label); 33 | return await name?.getAttribute('textContent'); 34 | } 35 | 36 | /** 37 | * Get text of the Call Stack item. 38 | * @returns a promise resolving to Call Stack item text string 39 | */ 40 | async getText(): Promise { 41 | const value = await this.findElement(CallStackItem.locators.CallStackItem.text); 42 | return await value.getText(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/debug/DebugBreakpointSection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { WebElement } from 'selenium-webdriver'; 19 | import { ViewContent } from '../../ViewContent'; 20 | import { GenericCustomTreeSection } from '../custom/CustomTreeSection'; 21 | import { BreakpointSectionItem } from './BreakpointSectionItem'; 22 | 23 | export class DebugBreakpointSection extends GenericCustomTreeSection { 24 | constructor(panel: WebElement, viewContent: ViewContent) { 25 | super(panel, viewContent, BreakpointSectionItem); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/debug/DebugCallStackSection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { WebElement } from 'selenium-webdriver'; 19 | import { ViewContent } from '../../ViewContent'; 20 | import { GenericCustomTreeSection } from '../custom/CustomTreeSection'; 21 | import { CallStackItem } from './CallStackItem'; 22 | 23 | export class DebugCallStackSection extends GenericCustomTreeSection { 24 | constructor(panel: WebElement, viewContent: ViewContent) { 25 | super(panel, viewContent, CallStackItem); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/debug/DebugVariablesSection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { WebElement } from 'selenium-webdriver'; 19 | import { ViewContent } from '../../ViewContent'; 20 | import { GenericCustomTreeSection } from '../custom/CustomTreeSection'; 21 | import { VariableSectionItem } from './VariableSectionItem'; 22 | 23 | export class DebugVariableSection extends GenericCustomTreeSection { 24 | constructor(panel: WebElement, viewContent: ViewContent) { 25 | super(panel, viewContent, VariableSectionItem); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/debug/SectionBreakpoint.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { ElementWithContextMenu } from '../../../ElementWithContextMenu'; 19 | 20 | export class SectionBreakpoint extends ElementWithContextMenu {} 21 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/debug/WatchSection.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { Key, WebElement } from 'selenium-webdriver'; 19 | import { ViewContent } from '../../ViewContent'; 20 | import { GenericCustomTreeSection } from '../custom/CustomTreeSection'; 21 | import { WatchSectionItem } from './WatchSectionItem'; 22 | 23 | export class WatchSection extends GenericCustomTreeSection { 24 | constructor(panel: WebElement, viewContent: ViewContent) { 25 | super(panel, viewContent, WatchSectionItem); 26 | } 27 | 28 | /** 29 | * Add item to Watch section. 30 | * @param name 31 | */ 32 | async addItem(name: string): Promise { 33 | await (await this.getAction(WatchSection.locators.WatchSection.addExpression))?.click(); 34 | await new Promise((res) => setTimeout(res, 1000)); 35 | const textInput = await this.findElement(WatchSection.locators.WatchSection.input); 36 | await textInput.clear(); 37 | await textInput.sendKeys(name + Key.ENTER); 38 | } 39 | 40 | /** 41 | * Click on 'Refresh' button. 42 | */ 43 | async refresh(): Promise { 44 | await (await this.getAction(WatchSection.locators.WatchSection.refresh))?.click(); 45 | } 46 | 47 | /** 48 | * Remove all items in Watch seection by using 'Remove All Expression' button. 49 | */ 50 | async removeAllExpressions(): Promise { 51 | await (await this.getAction(WatchSection.locators.WatchSection.removeAll))?.click(); 52 | } 53 | 54 | /** 55 | * Collapse all items in Watch section by using 'Collapse All' button. 56 | */ 57 | async collapseAll(): Promise { 58 | await (await this.getAction(WatchSection.locators.WatchSection.collapseAll))?.click(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/sidebar/tree/debug/WatchSectionItem.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { WebElement } from 'selenium-webdriver'; 19 | import { TreeSection } from '../TreeSection'; 20 | import { CustomTreeItem } from '../custom/CustomTreeItem'; 21 | 22 | export class WatchSectionItem extends CustomTreeItem { 23 | constructor(element: WebElement, viewPart: TreeSection) { 24 | super(element, viewPart); 25 | } 26 | 27 | /** 28 | * Get label of the Watch section item. 29 | * @returns a promise resolving to Watch section item label string 30 | */ 31 | async getLabel(): Promise { 32 | const name = await this.findElement(WatchSectionItem.locators.WatchSectionItem.label); 33 | return await name?.getAttribute('textContent'); 34 | } 35 | 36 | /** 37 | * Get value of the Watch section item. 38 | * @returns a promise resolving to Watch section value label string 39 | */ 40 | async getValue(): Promise { 41 | const value = await this.findElement(WatchSectionItem.locators.WatchSectionItem.value); 42 | return await value.getText(); 43 | } 44 | 45 | /** 46 | * Remove item from Watch section. 47 | */ 48 | async remove(): Promise { 49 | const button = await this.getActionButton(WatchSectionItem.locators.WatchSectionItem.remove); 50 | await button?.click(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/page-objects/src/components/workbench/input/QuickOpenBox.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { Input, QuickPickItem } from '../../..'; 19 | import { until } from 'selenium-webdriver'; 20 | 21 | /** 22 | * @deprecated as of VS Code 1.44.0, quick open box has been replaced with input box 23 | * The quick open box variation of the input 24 | */ 25 | export class QuickOpenBox extends Input { 26 | constructor() { 27 | super(QuickOpenBox.locators.QuickOpenBox.constructor, QuickOpenBox.locators.Workbench.constructor); 28 | } 29 | 30 | /** 31 | * Construct a new QuickOpenBox instance after waiting for its underlying element to exist 32 | * Use when a quick open box is scheduled to appear. 33 | */ 34 | static async create(): Promise { 35 | await QuickOpenBox.driver.wait(until.elementLocated(QuickOpenBox.locators.QuickOpenBox.constructor)); 36 | return new QuickOpenBox().wait(); 37 | } 38 | 39 | async hasProgress(): Promise { 40 | const klass = await this.findElement(QuickOpenBox.locators.QuickOpenBox.progress).getAttribute('class'); 41 | return klass.indexOf('done') < 0; 42 | } 43 | 44 | async getQuickPicks(): Promise { 45 | const picks: QuickPickItem[] = []; 46 | const tree = await this.getDriver().wait(until.elementLocated(QuickOpenBox.locators.QuickOpenBox.quickList), 1000); 47 | const elements = await tree.findElements(QuickOpenBox.locators.QuickOpenBox.row); 48 | for (const element of elements) { 49 | const index = +(await element.getAttribute('aria-posinset')); 50 | if (await element.isDisplayed()) { 51 | picks.push(await new QuickPickItem(index, this).wait()); 52 | } 53 | } 54 | return picks; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/page-objects/src/conditions/WaitForAttribute.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { WebElement } from 'selenium-webdriver'; 19 | 20 | /** 21 | * Condition to wait until an element's attribute has a specified value 22 | * @param element WebElement to check 23 | * @param attribute attribute to check 24 | * @param value value to wait for the attribute to have 25 | */ 26 | export function waitForAttributeValue(element: WebElement, attribute: string, value: string) { 27 | return async () => { 28 | const result = await element.getAttribute(attribute); 29 | return result === value; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /packages/page-objects/src/errors/NullAttributeError.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | export class NullAttributeError extends Error { 19 | constructor(message?: string) { 20 | super(message); 21 | this.name = 'NullAttributeError'; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/page-objects/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "out", 5 | "rootDir": "src" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /tests/test-project/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | node_modules/ 3 | *.vsix 4 | test-resources/ 5 | test-extensions/ -------------------------------------------------------------------------------- /tests/test-project/.mocharc-debug.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | timeout: 1000000, 3 | failZero: true, 4 | }; 5 | -------------------------------------------------------------------------------- /tests/test-project/.mocharc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | timeout: 10000, 3 | failZero: true, 4 | }; 5 | -------------------------------------------------------------------------------- /tests/test-project/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "window.title": "${activeEditorShort}${separator}folder: ${rootPath}", 3 | "window.zoomLevel": -1 4 | } 5 | -------------------------------------------------------------------------------- /tests/test-project/.vscodeignore: -------------------------------------------------------------------------------- 1 | src/** 2 | test-resources/** 3 | test-extensions/** 4 | **/*.ts 5 | **/*.d.ts 6 | **/tsconfig.json 7 | resources/** 8 | ../../** 9 | out/test/** -------------------------------------------------------------------------------- /tests/test-project/README.md: -------------------------------------------------------------------------------- 1 | # ExTester - Test Project 2 | 3 | This is a simple extension for a VS Code dedicated to self-testing the ExTester framework. 4 | -------------------------------------------------------------------------------- /tests/test-project/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/tests/test-project/icons/logo.png -------------------------------------------------------------------------------- /tests/test-project/media/catScratch.css: -------------------------------------------------------------------------------- 1 | body { 2 | justify-content: center; 3 | align-items: center; 4 | margin: 1em 2em; 5 | background-image: url(./sand.jpg); 6 | background-repeat: repeat; 7 | } 8 | 9 | body.vscode-dark { 10 | background-image: url(./sand-dark.jpg); 11 | } 12 | 13 | .notes { 14 | display: grid; 15 | grid-template-columns: repeat(auto-fill, 100px); 16 | grid-template-rows: repeat(auto-fill, 100px); 17 | grid-gap: 2em; 18 | justify-content: center; 19 | } 20 | 21 | .note { 22 | display: flex; 23 | flex-direction: column; 24 | border-radius: 5px; 25 | background-color: var(--vscode-editor-background); 26 | text-align: center; 27 | padding: 0.6em; 28 | position: relative; 29 | overflow: hidden; 30 | } 31 | 32 | .note .text { 33 | flex: 1; 34 | font-size: 3em; 35 | display: flex; 36 | justify-content: center; 37 | align-items: center; 38 | } 39 | 40 | .note .created { 41 | font-style: italic; 42 | font-size: 0.75em; 43 | } 44 | 45 | .add-button { 46 | height: 100px; 47 | display: flex; 48 | justify-content: center; 49 | align-items: center; 50 | } 51 | 52 | .delete-button { 53 | position: absolute; 54 | top: 0; 55 | right: 0; 56 | display: none; 57 | } 58 | 59 | .delete-button:before { 60 | content: 'delete'; 61 | } 62 | 63 | .note:hover .delete-button { 64 | display: block; 65 | } 66 | -------------------------------------------------------------------------------- /tests/test-project/media/paw-color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/test-project/media/paw-outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/test-project/media/pawDraw.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | .drawing-canvas { 7 | width: 100%; 8 | height: 100%; 9 | flex: 1; 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | background-repeat: repeat; 14 | flex-direction: column; 15 | } 16 | 17 | .drawing-controls { 18 | position: fixed; 19 | bottom: 0; 20 | left: 0; 21 | width: 100%; 22 | display: flex; 23 | justify-content: center; 24 | } 25 | 26 | .drawing-controls button { 27 | position: relative; 28 | width: 100px; 29 | height: 100px; 30 | background: none; 31 | border: none; 32 | transform: translateY(30%); 33 | transition: transform 0.1s linear; 34 | outline: none; 35 | } 36 | 37 | .drawing-controls button:disabled { 38 | opacity: 0.5; 39 | } 40 | 41 | .drawing-controls button.active:not(:disabled), 42 | .drawing-controls button:hover:not(:disabled) { 43 | transform: translateY(10%); 44 | } 45 | 46 | .drawing-controls button:before, 47 | .drawing-controls button:after { 48 | display: block; 49 | content: ''; 50 | position: absolute; 51 | top: 0; 52 | left: 0; 53 | width: 100%; 54 | height: 100%; 55 | } 56 | 57 | .drawing-controls button:before { 58 | -webkit-mask: url('./paw-color.svg') no-repeat 50% 50%; 59 | } 60 | 61 | .drawing-controls button:after { 62 | background-color: #111; 63 | -webkit-mask: url('./paw-outline.svg') no-repeat 50% 50%; 64 | } 65 | 66 | .drawing-controls button.black:before { 67 | background-color: #333; 68 | } 69 | 70 | .drawing-controls button.white:before { 71 | background-color: white; 72 | } 73 | 74 | .drawing-controls button.red:before { 75 | background-color: red; 76 | } 77 | 78 | .drawing-controls button.green:before { 79 | background-color: green; 80 | } 81 | 82 | .drawing-controls button.blue:before { 83 | background-color: blue; 84 | } 85 | -------------------------------------------------------------------------------- /tests/test-project/media/reset.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 13px; 4 | } 5 | 6 | *, 7 | *:before, 8 | *:after { 9 | box-sizing: inherit; 10 | } 11 | 12 | body, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | p, 20 | ol, 21 | ul { 22 | margin: 0; 23 | padding: 0; 24 | font-weight: normal; 25 | } 26 | 27 | img { 28 | max-width: 100%; 29 | height: auto; 30 | } 31 | -------------------------------------------------------------------------------- /tests/test-project/media/sand-dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/tests/test-project/media/sand-dark.jpg -------------------------------------------------------------------------------- /tests/test-project/media/sand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/tests/test-project/media/sand.jpg -------------------------------------------------------------------------------- /tests/test-project/media/vscode.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --container-paddding: 20px; 3 | --input-padding-vertical: 6px; 4 | --input-padding-horizontal: 4px; 5 | --input-margin-vertical: 4px; 6 | --input-margin-horizontal: 0; 7 | } 8 | 9 | body { 10 | padding: 0 var(--container-paddding); 11 | color: var(--vscode-foreground); 12 | font-size: var(--vscode-font-size); 13 | font-weight: var(--vscode-font-weight); 14 | font-family: var(--vscode-font-family); 15 | background-color: var(--vscode-editor-background); 16 | } 17 | 18 | ol, 19 | ul { 20 | padding-left: var(--container-paddding); 21 | } 22 | 23 | body > *, 24 | form > * { 25 | margin-block-start: var(--input-margin-vertical); 26 | margin-block-end: var(--input-margin-vertical); 27 | } 28 | 29 | *:focus { 30 | outline-color: var(--vscode-focusBorder) !important; 31 | } 32 | 33 | a { 34 | color: var(--vscode-textLink-foreground); 35 | } 36 | 37 | a:hover, 38 | a:active { 39 | color: var(--vscode-textLink-activeForeground); 40 | } 41 | 42 | code { 43 | font-size: var(--vscode-editor-font-size); 44 | font-family: var(--vscode-editor-font-family); 45 | } 46 | 47 | button { 48 | border: none; 49 | padding: var(--input-padding-vertical) var(--input-padding-horizontal); 50 | width: 100%; 51 | text-align: center; 52 | outline: 1px solid transparent; 53 | outline-offset: 2px !important; 54 | color: var(--vscode-button-foreground); 55 | background: var(--vscode-button-background); 56 | } 57 | 58 | button:hover { 59 | cursor: pointer; 60 | background: var(--vscode-button-hoverBackground); 61 | } 62 | 63 | button:focus { 64 | outline-color: var(--vscode-focusBorder); 65 | } 66 | 67 | button.secondary { 68 | color: var(--vscode-button-secondaryForeground); 69 | background: var(--vscode-button-secondaryBackground); 70 | } 71 | 72 | button.secondary:hover { 73 | background: var(--vscode-button-secondaryHoverBackground); 74 | } 75 | 76 | input:not([type='checkbox']), 77 | textarea { 78 | display: block; 79 | width: 100%; 80 | border: none; 81 | font-family: var(--vscode-font-family); 82 | padding: var(--input-padding-vertical) var(--input-padding-horizontal); 83 | color: var(--vscode-input-foreground); 84 | outline-color: var(--vscode-input-border); 85 | background-color: var(--vscode-input-background); 86 | } 87 | 88 | input::placeholder, 89 | textarea::placeholder { 90 | color: var(--vscode-input-placeholderForeground); 91 | } 92 | -------------------------------------------------------------------------------- /tests/test-project/resources/debug-project/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "Test Launch", 8 | "skipFiles": [ 9 | "/**" 10 | ], 11 | "program": "${workspaceFolder}/test.js", 12 | "outFiles": [ 13 | "${workspaceFolder}/test.js" 14 | ], 15 | "runtimeExecutable": "node" 16 | }, 17 | { 18 | "type": "node", 19 | "request": "launch", 20 | "name": "Test Launch2", 21 | "skipFiles": [ 22 | "/**" 23 | ], 24 | "program": "${workspaceFolder}/test.js", 25 | "outFiles": [ 26 | "${workspaceFolder}/test.js" 27 | ], 28 | "runtimeExecutable": "${env:NODE}" 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /tests/test-project/resources/debug-project/test.js: -------------------------------------------------------------------------------- 1 | const line = 'line'; 2 | const num = 5; 3 | const bool = false; 4 | for (let i = 1; i < 10; i++) { 5 | console.log(`${line}${i}`); 6 | } 7 | setTimeout(() => { 8 | console.log('done'); 9 | }, 2000); -------------------------------------------------------------------------------- /tests/test-project/resources/example.cscratch: -------------------------------------------------------------------------------- 1 | { 2 | "scratches": [ 3 | { 4 | "id": "8lYOoWqz2rHtPuhvnZ43eMx1mG6WnFrm", 5 | "text": "😸", 6 | "created": 1584577931699 7 | }, 8 | { 9 | "id": "aZ57bJUEaXZ5wuBAX6NfGuj85Y6iw84N", 10 | "text": "😻", 11 | "created": 1584577933329 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /tests/test-project/resources/file-with-spaces.ts: -------------------------------------------------------------------------------- 1 | first row 2 | second row 3 | third row 4 | -------------------------------------------------------------------------------- /tests/test-project/resources/file-with-tabs.ts: -------------------------------------------------------------------------------- 1 | first row 2 | second row 3 | third row 4 | -------------------------------------------------------------------------------- /tests/test-project/resources/icons/dark/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test-project/resources/icons/light/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test-project/resources/test-file-a.txt: -------------------------------------------------------------------------------- 1 | a -------------------------------------------------------------------------------- /tests/test-project/resources/test-file-b.txt: -------------------------------------------------------------------------------- 1 | b -------------------------------------------------------------------------------- /tests/test-project/resources/test-file.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/tests/test-project/resources/test-file.ts -------------------------------------------------------------------------------- /tests/test-project/resources/test-folder/foo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/tests/test-project/resources/test-folder/foo -------------------------------------------------------------------------------- /tests/test-project/resources/test-folder/foolder/bar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-extension-tester/aba24cc773f8519a50adc073e1701ff12133866d/tests/test-project/resources/test-folder/foolder/bar -------------------------------------------------------------------------------- /tests/test-project/src/codelensProvider.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as vscode from 'vscode'; 7 | 8 | /** 9 | * CodelensProvider 10 | */ 11 | export class CodelensProvider implements vscode.CodeLensProvider { 12 | private codeLenses: vscode.CodeLens[] = []; 13 | private regex: RegExp; 14 | private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter(); 15 | public readonly onDidChangeCodeLenses: vscode.Event = this._onDidChangeCodeLenses.event; 16 | 17 | constructor() { 18 | this.regex = /(\w+)/g; 19 | 20 | vscode.workspace.onDidChangeConfiguration(() => { 21 | this._onDidChangeCodeLenses.fire(); 22 | }); 23 | } 24 | 25 | public provideCodeLenses(document: vscode.TextDocument): vscode.CodeLens[] | Thenable { 26 | if (vscode.workspace.getConfiguration('testProject').get('enableCodeLens', true)) { 27 | this.codeLenses = []; 28 | const regex = new RegExp(this.regex); 29 | const text = document.getText(); 30 | let matches: RegExpExecArray | null; 31 | while ((matches = regex.exec(text)) !== null) { 32 | const line = document.lineAt(document.positionAt(matches.index).line); 33 | const indexOf = line.text.indexOf(matches[0]); 34 | const position = new vscode.Position(line.lineNumber, indexOf); 35 | const range = document.getWordRangeAtPosition(position, new RegExp(this.regex)); 36 | if (range) { 37 | this.codeLenses.push(new vscode.CodeLens(range)); 38 | } 39 | } 40 | return this.codeLenses; 41 | } 42 | return []; 43 | } 44 | 45 | public resolveCodeLens(codeLens: vscode.CodeLens) { 46 | if (vscode.workspace.getConfiguration('testProject').get('enableCodeLens', true)) { 47 | codeLens.command = { 48 | title: 'Codelens provided by sample extension', 49 | tooltip: 'Tooltip provided by sample extension', 50 | command: 'extension.codelensAction', 51 | arguments: ['Argument 1', false], 52 | }; 53 | return codeLens; 54 | } 55 | return null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/test-project/src/test/01_general/resource.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | import { error, TitleBar, VSBrowser } from 'vscode-extension-tester'; 20 | import * as os from 'os'; 21 | import * as path from 'path'; 22 | 23 | async function getTitle(): Promise<[string | undefined, Error | undefined]> { 24 | try { 25 | const titleBar = new TitleBar(); 26 | const title = await titleBar.getTitle(); 27 | return [title, undefined]; 28 | } catch (e) { 29 | if (e instanceof error.InvalidSelectorError) { 30 | throw e; 31 | } 32 | return [undefined, new Error((e as Error).message)]; 33 | } 34 | } 35 | 36 | describe('Open resource test', function () { 37 | this.timeout(30000); 38 | 39 | it('Single folder is open from CLI', async function () { 40 | let lastError = new Error('Could not get title from TitleBar.'); 41 | const prefix = 'folder: '; 42 | 43 | await VSBrowser.instance.driver.wait( 44 | async () => { 45 | const [title, error] = await getTitle(); 46 | lastError = error ?? lastError; 47 | 48 | const index = title?.indexOf(prefix) ?? 0; 49 | 50 | let openFolderPath = title?.slice(index + prefix.length); 51 | if (openFolderPath) { 52 | if (openFolderPath.startsWith('~/')) { 53 | openFolderPath = path.join(os.homedir(), openFolderPath.slice(2)); 54 | } 55 | 56 | expect(openFolderPath.split(' ')[0]).equals(process.cwd()); 57 | return true; 58 | } 59 | 60 | return false; 61 | }, 62 | this.timeout() - 2000, 63 | lastError.toString(), 64 | ); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /tests/test-project/src/test/activityBar/actionsControl.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | import { ActivityBar, ActionsControl } from 'vscode-extension-tester'; 20 | 21 | (process.platform === 'darwin' ? describe.skip : describe)('ActionsControl', () => { 22 | let bar: ActivityBar; 23 | let control: ActionsControl | undefined; 24 | 25 | before(async function () { 26 | bar = new ActivityBar(); 27 | control = await bar.getGlobalAction('Manage'); 28 | }); 29 | 30 | it('openActionsMenu displays context menu', async () => { 31 | const menu = await control?.openActionMenu(); 32 | expect(await menu?.isDisplayed()).is.true; 33 | await menu?.close(); 34 | }); 35 | 36 | it('getTitle returns the action container label', async () => { 37 | const title = await control?.getTitle(); 38 | expect(title).equals('Manage'); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /tests/test-project/src/test/activityBar/activityBar.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | import { ActivityBar } from 'vscode-extension-tester'; 20 | 21 | describe('ActivityBar', () => { 22 | let bar: ActivityBar; 23 | 24 | before(() => { 25 | bar = new ActivityBar(); 26 | }); 27 | 28 | it('getViewControls finds view containers', async () => { 29 | const controls = await bar.getViewControls(); 30 | expect(controls.length).greaterThan(0); 31 | }); 32 | 33 | it('getViewControl works with the correct label', async () => { 34 | const explorer = await bar.getViewControl('Explorer'); 35 | expect(explorer).not.undefined; 36 | }); 37 | 38 | it('getViewControl returns undefined with an invalid label', async () => { 39 | const item = await bar.getViewControl('whatever'); 40 | expect(item).undefined; 41 | }); 42 | 43 | it('getGlobalActions finds global action containers', async () => { 44 | const actions = await bar.getGlobalActions(); 45 | expect(actions.length).greaterThan(0); 46 | }); 47 | 48 | it('getGlobalAction finds action container with the given label', async () => { 49 | const action = await bar.getGlobalAction('Manage'); 50 | expect(action).not.undefined; 51 | }); 52 | 53 | it('getGlobalAction returns undefined with nonexistent label', async () => { 54 | const action = await bar.getGlobalAction('whatever'); 55 | expect(action).undefined; 56 | }); 57 | 58 | (process.platform === 'darwin' ? it.skip : it)('openContextMenu shows context menu', async () => { 59 | const menu = await bar.openContextMenu(); 60 | expect(await menu.isDisplayed()).is.true; 61 | await menu.close(); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /tests/test-project/src/test/activityBar/viewControl.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | import { ActivityBar, ViewControl } from 'vscode-extension-tester'; 20 | 21 | describe('ViewControl', () => { 22 | let bar: ActivityBar; 23 | let control: ViewControl | undefined; 24 | 25 | before(async () => { 26 | bar = new ActivityBar(); 27 | control = await bar.getViewControl('Explorer'); 28 | }); 29 | 30 | it('openView opens the underlying view', async () => { 31 | const view = await control?.openView(); 32 | const klass = await control?.getAttribute('class'); 33 | 34 | expect(klass?.indexOf('checked')).greaterThan(-1); 35 | expect(await view?.isDisplayed()).is.true; 36 | 37 | const title = await view?.getTitlePart().getTitle(); 38 | expect(title?.toLowerCase()).equals('explorer'); 39 | }); 40 | 41 | it('closeView closes the side bar view', async () => { 42 | await control?.openView(); 43 | await control?.closeView(); 44 | 45 | const klass = await control?.getAttribute('class'); 46 | expect(klass?.indexOf('checked')).lessThan(0); 47 | }); 48 | 49 | it('getTitle returns container label', async () => { 50 | const title = await control?.getTitle(); 51 | expect(title).has.string('Explorer'); 52 | }); 53 | 54 | (process.platform === 'darwin' ? it.skip : it)('openContextMenu shows context menu', async () => { 55 | const menu = await control?.openContextMenu(); 56 | expect(await menu?.isDisplayed()).is.true; 57 | await menu?.close(); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /tests/test-project/src/test/cli/order-1.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | 20 | describe('CLI blob order test - 1', function () { 21 | it('Executed as last test', function () { 22 | expect(process.env['CLI_ORDER'], 'this test should executed after order-2.test.ts').equal('2'); 23 | process.env['CLI_ORDER'] = '1'; 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/test-project/src/test/cli/order-2.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | 20 | describe('CLI blob order test - 2', function () { 21 | it('Executed as middle test', function () { 22 | expect(process.env['CLI_ORDER'], 'this test should executed after order-3.test.ts').equal('3'); 23 | process.env['CLI_ORDER'] = '2'; 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/test-project/src/test/cli/order-3.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | 20 | describe('CLI blob order test - 3', function () { 21 | it('Executed as first test', function () { 22 | expect(process.env['CLI_ORDER'], `other test was executed first`).to.be.undefined; 23 | process.env['CLI_ORDER'] = '3'; 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/test-project/src/test/menu/contextMenu.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { TitleBar, ContextMenu, before, beforeEach, VSBrowser } from 'vscode-extension-tester'; 19 | import { expect } from 'chai'; 20 | import * as path from 'path'; 21 | 22 | (process.platform === 'darwin' ? describe.skip : describe)('ContextMenu', function () { 23 | let bar: TitleBar; 24 | let menu: ContextMenu; 25 | 26 | before(async () => { 27 | this.timeout(30000); 28 | await VSBrowser.instance.openResources(path.resolve(__dirname, '..', '..', '..', 'resources', 'test-folder')); 29 | await VSBrowser.instance.driver.sleep(5000); 30 | }); 31 | 32 | beforeEach(async function () { 33 | bar = new TitleBar(); 34 | menu = (await bar.select('File')) as ContextMenu; 35 | }); 36 | 37 | it('getItems finds all menu items', async function () { 38 | this.timeout(5000); 39 | const items = await menu.getItems(); 40 | await menu.close(); 41 | expect(items).not.empty; 42 | }); 43 | 44 | it('getItem finds an item with the given name', async function () { 45 | this.timeout(5000); 46 | const item = await menu.getItem('New File...'); 47 | await menu.close(); 48 | expect(item).not.undefined; 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /tests/test-project/src/test/menu/macTitleBar.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { EditorView, MacTitleBar, OutputView } from 'vscode-extension-tester'; 19 | import { AssertionError, expect } from 'chai'; 20 | 21 | describe.skip('MacTitleBar', () => { 22 | beforeEach(async () => { 23 | await new Promise((res) => setTimeout(res, 2000)); 24 | await new EditorView().closeAllEditors(); 25 | }); 26 | 27 | it('works with a single context menu', async () => { 28 | MacTitleBar.select('File', 'New File'); 29 | const view = new EditorView(); 30 | expect(await view.getOpenEditorTitles()).to.include('Untitled-1'); 31 | }); 32 | 33 | it('works with a different menu', async () => { 34 | MacTitleBar.select('View', 'Output'); 35 | const output = new OutputView(); 36 | expect(await output.isDisplayed()).to.be.true; 37 | }); 38 | 39 | it('work with a nested submenu', async () => { 40 | MacTitleBar.select('Code', 'Preferences', 'Settings'); 41 | const view = new EditorView(); 42 | expect(await view.getOpenEditorTitles()).to.include('Settings'); 43 | }); 44 | 45 | it('errors when an item does not exist', () => { 46 | try { 47 | MacTitleBar.select('File', 'This does not exist'); 48 | expect.fail('no error was produced'); 49 | } catch (err) { 50 | if (err instanceof AssertionError) { 51 | throw err; 52 | } 53 | expect(err).not.to.be.empty; 54 | } 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /tests/test-project/src/test/system/clipboard.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { expect } from 'chai'; 19 | 20 | describe('System clipboard', function () { 21 | it('Should contains same text as before tests were run', async function () { 22 | const cb = await import('clipboardy'); 23 | const clipboard = cb.default.readSync(); 24 | expect(clipboard.startsWith('hello_ExTester'), `Fail, the clipboard is: '${clipboard}'`).to.be.true; 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/test-project/src/test/workbench/open.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License", destination); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import { EditorView, VSBrowser, Workbench } from 'vscode-extension-tester'; 19 | import * as path from 'path'; 20 | 21 | describe('Simple open file dialog', function () { 22 | const filePath = path.resolve('.', 'package.json'); 23 | 24 | after(async function () { 25 | await new EditorView().closeAllEditors(); 26 | }); 27 | 28 | it('Opens a file', async function () { 29 | this.timeout(30000); 30 | const input = await new Workbench().openCommandPrompt(); 31 | await input.setText('>File: Open File...'); 32 | await input.selectQuickPick('File: Open File...'); 33 | await new Promise((res) => setTimeout(res, 1000)); 34 | await input.setText(filePath); 35 | 36 | await VSBrowser.instance.driver.wait( 37 | async () => { 38 | try { 39 | await input.confirm(); 40 | await new Promise((res) => setTimeout(res, 1000)); 41 | return (await new EditorView().openEditor('package.json')).isDisplayed(); 42 | } catch { 43 | return false; 44 | } 45 | }, 46 | this.timeout() - 10000, 47 | `No editor with title 'package.json' available.`, 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /tests/test-project/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "out", 5 | "rootDir": "src", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true 8 | }, 9 | "include": ["src"] 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2023", 5 | "lib": ["ES2023"], 6 | "sourceMap": true, 7 | "strict": true, 8 | "noUnusedLocals": true, 9 | "experimentalDecorators": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "resolveJsonModule": true, 12 | "declaration": true 13 | }, 14 | "exclude": ["node_modules"] 15 | } 16 | --------------------------------------------------------------------------------