├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── SECURITY.md ├── plugins ├── cobol-language-support.yaml ├── cobol.yaml ├── debugger-for-mainframe.yaml ├── explorer-for-endevor.yaml └── hlasm-language-support.yaml └── tests ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .huskyrc ├── .lintstagedrc ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── package.json ├── src ├── cypressEnv.ts ├── debug.ts ├── e4e.ts ├── flow.ts ├── index.ts ├── languageSupport.ts ├── selectors.ts ├── symdump.ts ├── theiaActions.ts └── zowe.ts ├── tsconfig.json └── yarn.lock /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | This file includes the major changes to the Eclipse Che4z Basic and Premium stacks. 2 | 3 | ## [2.2] 2020-12-18 4 | 5 | - Zowe Explorer updated to version 1.11.0 6 | - Explorer for Endevor updated to version 1.11.1. ([Changelog](https://github.com/eclipse/che-che4z-explorer-for-endevor/blob/master/CHANGELOG.md)). 7 | - COBOL Language Support updated to version 0.16.1 ([Changelog](https://github.com/eclipse/che-che4z-lsp-for-cobol/blob/development/CHANGELOG.md)). 8 | - Debugger for Mainframe updated to version 1.3.1 ([Changelog](https://github.com/BroadcomMFD/debugger-for-mainframe/blob/master/CHANGELOG.md)). 9 | 10 | 11 | ## [2.1] 2020-08-21 12 | 13 | - Zowe Explorer updated to version 1.8.0 14 | - Explorer for Endevor updated to version 0.10.0. Users can now utilize their CA Endevor Plug-in for Zowe CLI profiles in Explorer for Endevor. ([Changelog](https://github.com/eclipse/che-che4z-explorer-for-endevor/blob/master/CHANGELOG.md)). 15 | - COBOL Language Support updated to version 0.13.0 ([Changelog](https://github.com/eclipse/che-che4z-lsp-for-cobol/blob/development/CHANGELOG.md)). 16 | - Debugger for Mainframe updated to version 1.2. Debugger for Mainframe now supports COBOL Batch programs as well as CICS programs. ([Changelog](https://github.com/BroadcomMFD/debugger-for-mainframe/blob/master/CHANGELOG.md)). 17 | 18 | 19 | ## [2.0] 2020-06-08 20 | 21 | - Zowe Explorer is now compatible with Eclipse Che v7.11. 22 | - Zowe CLI profiles can now be accessed by CLI plugins and other extensions simultaneously. 23 | - CA Secure Credential Store plug-in for Zowe CLI temporarily removed from the premium stack pending a bug fix. 24 | - Debugger for Mainframe updated to version 1.1 ([Changelog](https://github.com/BroadcomMFD/debugger-for-mainframe/blob/master/CHANGELOG.md)). 25 | - COBOL Language Support updated to version 0.11.1 ([Changelog](https://github.com/eclipse/che-che4z-lsp-for-cobol/blob/development/CHANGELOG.md)). 26 | 27 | ## [1.2.0] 2020-03-03 28 | 29 | - Updated versions of components added. 30 | 31 | ## [1.1.0] 2019-12-11 32 | 33 | - Debugger for Mainframe extension added to the basic and premium stacks. 34 | - HLASM Language Support extension added to the basic and premium stacks. 35 | 36 | ## [1.0.0] 2019-11-07 37 | 38 | - Initial release 39 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Code of Conduct 2 | 3 | **Version 2.0 4 | January 1, 2023** 5 | 6 | ## Our Pledge 7 | 8 | In the interest of fostering an open and welcoming environment, we as community members, contributors, Committers[^1], and Project Leads (collectively "Contributors") pledge to make participation in our projects and our community a harassment-free and inclusive experience for everyone. 9 | 10 | This Community Code of Conduct ("Code") outlines our behavior expectations as members of our community in all Eclipse Foundation activities, both offline and online. It is not intended to govern scenarios or behaviors outside of the scope of Eclipse Foundation activities. Nor is it intended to replace or supersede the protections offered to all our community members under the law. Please follow both the spirit and letter of this Code and encourage other Contributors to follow these principles into our work. Failure to read or acknowledge this Code does not excuse a Contributor from compliance with the Code. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contribute to creating a positive and professional environment include: 15 | 16 | - Using welcoming and inclusive language; 17 | - Actively encouraging all voices; 18 | - Helping others bring their perspectives and listening actively. If you find yourself dominating a discussion, it is especially important to encourage other voices to join in; 19 | - Being respectful of differing viewpoints and experiences; 20 | - Gracefully accepting constructive criticism; 21 | - Focusing on what is best for the community; 22 | - Showing empathy towards other community members; 23 | - Being direct but professional; and 24 | - Leading by example by holding yourself and others accountable 25 | 26 | Examples of unacceptable behavior by Contributors include: 27 | 28 | - The use of sexualized language or imagery; 29 | - Unwelcome sexual attention or advances; 30 | - Trolling, insulting/derogatory comments, and personal or political attacks; 31 | - Public or private harassment, repeated harassment; 32 | - Publishing others' private information, such as a physical or electronic address, without explicit permission; 33 | - Violent threats or language directed against another person; 34 | - Sexist, racist, or otherwise discriminatory jokes and language; 35 | - Posting sexually explicit or violent material; 36 | - Sharing private content, such as emails sent privately or non-publicly, or unlogged forums such as IRC channel history; 37 | - Personal insults, especially those using racist or sexist terms; 38 | - Excessive or unnecessary profanity; 39 | - Advocating for, or encouraging, any of the above behavior; and 40 | - Other conduct which could reasonably be considered inappropriate in a professional setting 41 | 42 | ## Our Responsibilities 43 | 44 | With the support of the Eclipse Foundation employees, consultants, officers, and directors (collectively, the "Staff"), Committers, and Project Leads, the Eclipse Foundation Conduct Committee (the "Conduct Committee") is responsible for clarifying the standards of acceptable behavior. The Conduct Committee takes appropriate and fair corrective action in response to any instances of unacceptable behavior. 45 | 46 | ## Scope 47 | 48 | This Code applies within all Project, Working Group, and Interest Group spaces and communication channels of the Eclipse Foundation (collectively, "Eclipse spaces"), within any Eclipse-organized event or meeting, and in public spaces when an individual is representing an Eclipse Foundation Project, Working Group, Interest Group, or their communities. Examples of representing a Project or community include posting via an official social media account, personal accounts, or acting as an appointed representative at an online or offline event. Representation of Projects, Working Groups, and Interest Groups may be further defined and clarified by Committers, Project Leads, or the Staff. 49 | 50 | ## Enforcement 51 | 52 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Conduct Committee via conduct@eclipse-foundation.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Without the explicit consent of the reporter, the Conduct Committee is obligated to maintain confidentiality with regard to the reporter of an incident. The Conduct Committee is further obligated to ensure that the respondent is provided with sufficient information about the complaint to reply. If such details cannot be provided while maintaining confidentiality, the Conduct Committee will take the respondent‘s inability to provide a defense into account in its deliberations and decisions. Further details of enforcement guidelines may be posted separately. 53 | 54 | Staff, Committers and Project Leads have the right to report, remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code, or to block temporarily or permanently any Contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Any such actions will be reported to the Conduct Committee for transparency and record keeping. 55 | 56 | Any Staff (including officers and directors of the Eclipse Foundation), Committers, Project Leads, or Conduct Committee members who are the subject of a complaint to the Conduct Committee will be recused from the process of resolving any such complaint. 57 | 58 | ## Responsibility 59 | 60 | The responsibility for administering this Code rests with the Conduct Committee, with oversight by the Executive Director and the Board of Directors. For additional information on the Conduct Committee and its process, please write to . 61 | 62 | ## Investigation of Potential Code Violations 63 | 64 | All conflict is not bad as a healthy debate may sometimes be necessary to push us to do our best. It is, however, unacceptable to be disrespectful or offensive, or violate this Code. If you see someone engaging in objectionable behavior violating this Code, we encourage you to address the behavior directly with those involved. If for some reason, you are unable to resolve the matter or feel uncomfortable doing so, or if the behavior is threatening or harassing, please report it following the procedure laid out below. 65 | 66 | Reports should be directed to . It is the Conduct Committee’s role to receive and address reported violations of this Code and to ensure a fair and speedy resolution. 67 | 68 | The Eclipse Foundation takes all reports of potential Code violations seriously and is committed to confidentiality and a full investigation of all allegations. The identity of the reporter will be omitted from the details of the report supplied to the accused. Contributors who are being investigated for a potential Code violation will have an opportunity to be heard prior to any final determination. Those found to have violated the Code can seek reconsideration of the violation and disciplinary action decisions. Every effort will be made to have all matters disposed of within 60 days of the receipt of the complaint. 69 | 70 | ## Actions 71 | Contributors who do not follow this Code in good faith may face temporary or permanent repercussions as determined by the Conduct Committee. 72 | 73 | This Code does not address all conduct. It works in conjunction with our [Communication Channel Guidelines](https://www.eclipse.org/org/documents/communication-channel-guidelines/), [Social Media Guidelines](https://www.eclipse.org/org/documents/social_media_guidelines.php), [Bylaws](https://www.eclipse.org/org/documents/eclipse-foundation-be-bylaws-en.pdf), and [Internal Rules](https://www.eclipse.org/org/documents/ef-be-internal-rules.pdf) which set out additional protections for, and obligations of, all contributors. The Foundation has additional policies that provide further guidance on other matters. 74 | 75 | It’s impossible to spell out every possible scenario that might be deemed a violation of this Code. Instead, we rely on one another’s good judgment to uphold a high standard of integrity within all Eclipse Spaces. Sometimes, identifying the right thing to do isn’t an easy call. In such a scenario, raise the issue as early as possible. 76 | 77 | ## No Retaliation 78 | 79 | The Eclipse community relies upon and values the help of Contributors who identify potential problems that may need to be addressed within an Eclipse Space. Any retaliation against a Contributor who raises an issue honestly is a violation of this Code. That a Contributor has raised a concern honestly or participated in an investigation, cannot be the basis for any adverse action, including threats, harassment, or discrimination. If you work with someone who has raised a concern or provided information in an investigation, you should continue to treat the person with courtesy and respect. If you believe someone has retaliated against you, report the matter as described by this Code. Honest reporting does not mean that you have to be right when you raise a concern; you just have to believe that the information you are providing is accurate. 80 | 81 | False reporting, especially when intended to retaliate or exclude, is itself a violation of this Code and will not be accepted or tolerated. 82 | 83 | Everyone is encouraged to ask questions about this Code. Your feedback is welcome, and you will get a response within three business days. Write to . 84 | 85 | ## Amendments 86 | 87 | The Eclipse Foundation Board of Directors may amend this Code from time to time and may vary the procedures it sets out where appropriate in a particular case. 88 | 89 | ### Attribution 90 | 91 | This Code was inspired by the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available [here](https://www.contributor-covenant.org/version/1/4/code-of-conduct/). 92 | 93 | [^1]: Capitalized terms used herein without definition shall have the meanings assigned to them in the Bylaws. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Eclipse Che4z 2 | 3 | Thanks for your interest in this project. 4 | 5 | ## Project description 6 | 7 | Eclipse Che4z provides an components/extensions for Eclipse Che to facilitate mainframe application development by providing: 8 | 9 | * https://projects.eclipse.org/projects/ecd.che.che4z 10 | 11 | ## Developer resources 12 | Information regarding source code management, builds, coding standards, and more. 13 | 14 | * https://projects.eclipse.org/projects/ecd.che.che4z/developer 15 | 16 | The project maintains the following source code repository 17 | 18 | * https://github.com/eclipse/che-che4z 19 | 20 | ## Eclipse Contributor Agreement 21 | 22 | Before your contribution can be accepted by the project team contributors must electronically sign the Eclipse Contributor Agreement (ECA). 23 | 24 | * http://www.eclipse.org/legal/ECA.php 25 | 26 | Commits that are provided by non-committers must have a Signed-off-by field in the footer indicating that the author is aware of the terms by which the contribution has been provided to the project. The non-committer must additionally have an Eclipse Foundation account and must have a signed Eclipse Contributor Agreement (ECA) on file. 27 | 28 | Make sure that the user email you specified on your local git is the same as on the Github account. 29 | 30 | For more information, please see the Eclipse Committer Handbook: 31 | https://www.eclipse.org/projects/handbook/#resources-commit 32 | 33 | ## Contact 34 | 35 | Contact the project developers. 36 | 37 | * supportChe4z.pdl@broadcom.com 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ./tests/LICENSE -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | # Third-party Content 2 | 3 | ## cypress-iframe@npm:1.0.1 4 | License: MIT 5 | Homepage: https://gitlab.com/kgroat/cypress-iframe#readme 6 | 7 | ## cypress-xpath@npm:1.6.2 8 | License: MIT 9 | Homepage: https://github.com/cypress-io/cypress-xpath#readme 10 | 11 | ## cypress@npm:7.1.0 12 | License: MIT 13 | Homepage: https://github.com/cypress-io/cypress 14 | 15 | ## eslint-config-prettier@npm:6.15.0 16 | License: MIT 17 | 18 | ## eslint-plugin-cypress@npm:2.11.2 19 | License: MIT 20 | Homepage: https://github.com/cypress-io/eslint-plugin-cypress#readme 21 | 22 | ## eslint-plugin-prettier@npm:3.4.0 23 | License: MIT 24 | Homepage: https://github.com/prettier/eslint-plugin-prettier#readme 25 | 26 | ## eslint@npm:7.24.0 27 | License: MIT 28 | Homepage: https://eslint.org 29 | 30 | ## husky@npm:4.3.8 31 | License: MIT 32 | Homepage: https://github.com/typicode/husky#readme 33 | 34 | ## lint-staged@npm:10.5.4 35 | License: MIT 36 | 37 | ## prettier@npm:2.2.1 38 | License: MIT 39 | Homepage: https://prettier.io 40 | 41 | ## typescript@patch:typescript@npm%3A4.2.4#~builtin::version=4.2.4&hash=701156 42 | License: Apache-2.0 43 | Homepage: https://www.typescriptlang.org/ 44 | 45 | ## yarn-lockfile@npm:1.1.1 46 | License: Unlicense 47 | Homepage: https://github.com/wmhilton/yarn-lockfile#readme 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Che4z 2 | 3 | Che4z is an all-in-one mainframe extension package for developers working with z/OS applications, suitable for all levels of mainframe experience, even beginners. 4 | 5 | Che4z offers mainframe application developers a modern, familiar and seamless experience, which helps to overcome some developers' reservations or concerns about the traditional mainframe user experience. 6 | 7 | Che4z is powered by the open-source projects [Eclipse Che](https://www.eclipse.org/che/docs/che-7) and [Zowe](https://www.zowe.org/). Many of these extensions, and other mainframe-oriented innovations, are also available as part of the Code4z package of extensions for Visual Studio Code. 8 | 9 | ## Installing Che4z 10 | 11 | 12 | ### Basic Stack 13 | 14 | The Che4z basic stack is included with Eclipse Che version 7.6.0 and above, so no installation is necessary. To get started, create a new workspace and select the **Mainframe Basic Stack**. 15 | 16 | ### Premium Stack 17 | 18 | To install the Che4z [premium stack](https://techdocs.broadcom.com/us/en/ca-mainframe-software/devops/ca-brightside/3-0/eclipse-che4z-premium-stack.html), **follow these steps**: 19 | 20 | 1. Open a [Brightside Support Ticket](https://support.broadcom.com/mainframe-software/product-page.html?productName=CA%20Brightside) to obtain the devfile URL for the Che4z premium stack. 21 | 22 | 2. Once you receive the URL, log in to Eclipse Che. 23 | 24 | 3. In **Workspaces**, click **Import Devfile**. 25 | 26 | 4. Next to **Source**, select **URL**. 27 | 28 | 5. In the **URL** field, paste the Eclipse Che4z premium stack devfile URL. 29 | 30 | 6. Click **Create & Open** and wait for the workspace to initialize. 31 | A workspace is created with Eclipse Che4z extensions available. 32 | 33 | ## Extensions 34 | 35 | The Che4z basic stack contains the COBOL Language Support, HLASM Language Support, Zowe Explorer, Explorer for Endevor and Debugger for Mainframe extensions. 36 | 37 | ### [COBOL Language Support](https://github.com/eclipse/che-che4z-lsp-for-cobol) 38 | [![GitHub issues](https://img.shields.io/github/issues-raw/eclipse/che-che4z-lsp-for-cobol?style=flat-square)](https://github.com/eclipse/che-che4z-lsp-for-cobol/issues) 39 | [![slack](https://img.shields.io/badge/chat-on%20Slack-blue?style=flat-square)](https://communityinviter.com/apps/che4z/code4z) 40 | 41 | COBOL Language Support standardizes the communication between language tooling and your code editor using the Language Server Protocol (LSP). 42 | 43 | > How can we improve COBOL Language Support? [Let us know on our Git repository](https://github.com/eclipse/che-che4z-lsp-for-cobol/issues) 44 | 45 | #### Features 46 | * Edit COBOL code with syntax highlighting, real time syntax validation, content assist and other advanced features. 47 | 48 | #### Blogs 49 | * [Beginner’s Guide: COBOL Made Easy](https://medium.com/modern-mainframe/beginners-guide-cobol-made-easy-introduction-ecf2f611ac76) 50 | 51 | ### [HLASM Language Support](https://github.com/eclipse/che-che4z-lsp-for-hlasm) 52 | [![GitHub issues](https://img.shields.io/github/issues-raw/eclipse/che-che4z-lsp-for-hlasm?style=flat-square)](https://github.com/eclipse/che-che4z-lsp-for-hlasm/issues) 53 | [![slack](https://img.shields.io/badge/chat-on%20Slack-blue?style=flat-square)](https://communityinviter.com/apps/che4z/code4z) 54 | 55 | Code completion, highlighting, browsing and validation for High Level Assembler language. 56 | 57 | > How can we improve HLASM Language Support? [Let us know on our Git repository](https://github.com/eclipse/che-che4z-lsp-for-hlasm/issues) 58 | 59 | #### Features 60 | * Edit HLASM code with syntax highlighting, real time syntax validation, content assist and other advanced features. 61 | * Trace HLASM macros. 62 | 63 | ### [Zowe Explorer](https://marketplace.visualstudio.com/items?itemName=Zowe.vscode-extension-for-zowe) 64 | [![GitHub issues](https://img.shields.io/github/issues-raw/zowe/vscode-extension-for-zowe?style=flat-square)](https://github.com/zowe/vscode-extension-for-zowe/issues) 65 | [![slack](https://img.shields.io/badge/chat-on%20Slack-blue?style=flat-square)](https://openmainframeproject.slack.com/) 66 | 67 | Zowe Explorer is an Eclipse Che extension powered by Zowe CLI that streamlines interaction with mainframe data sets, USS files, and jobs. 68 | 69 | > How can we improve Zowe Explorer? [Let us know on our Git repository](https://github.com/zowe/vscode-extension-for-zowe/issues) 70 | 71 | #### Features 72 | * Access z/OS Datasets and z/OS Unix file systems and submit JCLs. 73 | * View and download job output. 74 | * Issue TSO commands. 75 | 76 | #### Blogs 77 | * [Beginner’s Guide: How to access mainframe via Zowe in 10 easy steps](https://medium.com/zowe/beginners-guide-how-to-access-mainframe-via-zowe-in-10-easy-steps-fbec14ed6ed2) 78 | * [Zowe blog](https://medium.com/zowe) 79 | 80 | ### [Explorer for Endevor](https://github.com/eclipse/che-che4z-explorer-for-endevor) 81 | [![GitHub issues](https://img.shields.io/github/issues-raw/eclipse/che-che4z-explorer-for-endevor?style=flat-square)](https://github.com/eclipse/che-che4z-explorer-for-endevor/issues) 82 | [![slack](https://img.shields.io/badge/chat-on%20Slack-blue?style=flat-square)](https://communityinviter.com/apps/che4z/code4z) 83 | 84 | Explorer for Endevor gives you the ability to Browse and Retrieve [Endevor® SCM](https://www.broadcom.com/products/mainframe/devops-app-development/app/endevor-software-change-manager) elements using a user-friendly, intuitive interface. 85 | 86 | It offers the best developer experience in synergy with [Bridge for Git](https://youtu.be/sjnZuQpUVM4), a solution which enables you to concurrently work in Git and mainframe. 87 | 88 | > How can we improve Explorer for Endevor? [Let us know on our Git repository](https://github.com/eclipse/che-che4z-explorer-for-endevor/issues) 89 | 90 | #### Features 91 | * Retrieve, browse and search Endevor elements. 92 | 93 | ### [Debugger for Mainframe](https://github.com/BroadcomMFD/debugger-for-mainframe) 94 | [![GitHub issues](https://img.shields.io/github/issues-raw/broadcomMFD/debugger-for-mainframe?style=flat-square)](https://github.com/BroadcomMFD/debugger-for-mainframe/issues) 95 | [![slack](https://img.shields.io/badge/chat-on%20Slack-blue?style=flat-square)](https://communityinviter.com/apps/che4z/code4z) 96 | 97 | Debugger for Mainframe provides the debugging interface to [InterTest™ for CICS](https://www.broadcom.com/products/mainframe/devops-app-development/testing-quality/intertest-cics). This extension provides a modern debug experience for COBOL applications running in a CICS region. 98 | 99 | > How can we improve Debugger for Mainframe? [Let us know on our Git repository](https://github.com/BroadcomMFD/debugger-for-mainframe/issues) 100 | 101 | #### Features 102 | 103 | * Debug COBOL code for applications running in a CICS region. 104 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Che4z follows the Eclipse Vulnerability Reporting Policy. Vulnerabilities are tracked by the Eclipse security team, in cooperation with the Che4z project lead. Fixing vulnerabilities is taken care of by the Che4z project committers, with assistance and guidance of the security team. 4 | 5 | ## Supported Versions 6 | 7 | Che4z supports security updates only for the latest version. 8 | 9 | ## Reporting a Vulnerability 10 | 11 | We recommend that in case of suspected vulnerabilities you do not use the Che4z public issue tracker, but instead contact the Eclipse Security Team directly via security@eclipse.org. 12 | -------------------------------------------------------------------------------- /plugins/cobol-language-support.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | publisher: broadcommfd 3 | name: cobol-language-support 4 | version: 0.9.1 5 | type: VS Code extension 6 | displayName: COBOL Language Support 7 | title: COBOL Language Support 8 | description: COBOL Language Support standardizes the communication between language tooling and your code editor using the Language Server Protocol (LSP) 9 | icon: https://www.eclipse.org/che/images/logo-eclipseche.svg 10 | repository: https://github.com/eclipse/che-che4z-lsp-for-cobol 11 | category: Language 12 | spec: 13 | containers: 14 | - image: eclipse/che-remote-plugin-runner-java8:next 15 | memoryLimit: 512Mi 16 | extensions: 17 | - https://github.com/eclipse/che-che4z-lsp-for-cobol/releases/download/0.9.1/cobol-language-support-0.9.1.vsix -------------------------------------------------------------------------------- /plugins/cobol.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | publisher: bitlang 3 | name: cobol 4 | version: 5.0.6 5 | type: VS Code extension 6 | displayName: COBOL 7 | title: COBOL 8 | description: COBOL, JCL, PL/I & DIR syntax support 9 | icon: https://www.eclipse.org/che/images/logo-eclipseche.svg 10 | repository: https://github.com/spgennard/vscode_cobol 11 | category: Language 12 | spec: 13 | extensions: 14 | - https://github.com/eclipse/che-che4z/releases/download/1.0.0/cobol-5.0.6.vsix -------------------------------------------------------------------------------- /plugins/debugger-for-mainframe.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | publisher: broadcommfd 3 | name: debugger-for-mainframe 4 | version: 1.0.0 5 | type: VS Code extension 6 | displayName: Debugger for Mainframe 7 | title: Debugger for Mainframe 8 | description: Debugger for Mainframe provides the debugging interface to CA InterTest™. This extension provides a modern debug experience for COBOL applications running in a CICS region 9 | icon: https://www.eclipse.org/che/images/logo-eclipseche.svg 10 | repository: https://techdocs.broadcom.com/content/broadcom/techdocs/us/en/ca-mainframe-software/devops/ca-intertest-eclipse-help/11-0/ca-intertest-help.html 11 | category: Debugger 12 | spec: 13 | containers: 14 | - image: eclipse/che-remote-plugin-runner-java8:next 15 | memoryLimit: 512Mi 16 | extensions: 17 | - https://github.com/eclipse/che-che4z/releases/download/1.1.0/debugger-for-mainframe-1.0.0.vsix -------------------------------------------------------------------------------- /plugins/explorer-for-endevor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | publisher: broadcommfd 3 | name: explorer-for-endevor 4 | version: 0.9.0 5 | type: VS Code extension 6 | displayName: Explorer for Endevor 7 | title: Explorer for Endevor 8 | description: Explorer for Endevor 9 | icon: https://www.eclipse.org/che/images/logo-eclipseche.svg 10 | repository: https://github.com/eclipse/che-che4z-explorer-for-endevor 11 | category: Language 12 | spec: 13 | extensions: 14 | - https://github.com/eclipse/che-che4z/releases/download/1.0.0/explorer-for-endevor-0.9.0.vsix -------------------------------------------------------------------------------- /plugins/hlasm-language-support.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | publisher: broadcommfd 3 | name: hlasm-language-support 4 | version: 0.8.1 5 | type: VS Code extension 6 | displayName: HLASM Language Support 7 | title: HLASM Language Support 8 | description: Code completion, highlighting, browsing and validation for High Level Assembler 9 | icon: https://www.eclipse.org/che/images/logo-eclipseche.svg 10 | repository: https://github.com/eclipse/che-che4z-lsp-for-hlasm 11 | category: Language 12 | spec: 13 | extensions: 14 | - https://github.com/eclipse/che-che4z/releases/download/1.1.0/hlasm-language-support-0.8.1.vsix -------------------------------------------------------------------------------- /tests/.eslintignore: -------------------------------------------------------------------------------- 1 | package.json 2 | node_modules 3 | *.md 4 | -------------------------------------------------------------------------------- /tests/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:prettier/recommended", 10 | "plugin:cypress/recommended", 11 | "plugin:@typescript-eslint/recommended" 12 | ], 13 | "parser": "@typescript-eslint/parser", 14 | "parserOptions": { 15 | "ecmaVersion": 6 16 | }, 17 | "plugins": [ 18 | "cypress", 19 | "@typescript-eslint" 20 | ], 21 | "rules": { 22 | "no-trailing-spaces": "error", 23 | "indent": ["warn", 2], 24 | "prefer-const": "error", 25 | "no-var": "error", 26 | "@typescript-eslint/ban-ts-comment": "off", 27 | "cypress/no-unnecessary-waiting": "warn" 28 | } 29 | } -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pidsyar 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | 118 | # Cypress 119 | cypress/videos 120 | cypress/screenshots -------------------------------------------------------------------------------- /tests/.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "lint-staged" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | '**/*.+(js|ts)': [ 3 | 'eslint --no-ignore --color', 4 | 'prettier --write', 5 | 'git add', 6 | ], 7 | } -------------------------------------------------------------------------------- /tests/.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /tests/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma": "all", 7 | "proseWrap": "always", 8 | "endOfLine":"auto" 9 | } -------------------------------------------------------------------------------- /tests/LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 2.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 4 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION 5 | OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial content 12 | Distributed under this Agreement, and 13 | 14 | b) in the case of each subsequent Contributor: 15 | i) changes to the Program, and 16 | ii) additions to the Program; 17 | where such changes and/or additions to the Program originate from 18 | and are Distributed by that particular Contributor. A Contribution 19 | "originates" from a Contributor if it was added to the Program by 20 | such Contributor itself or anyone acting on such Contributor's behalf. 21 | Contributions do not include changes or additions to the Program that 22 | are not Modified Works. 23 | 24 | "Contributor" means any person or entity that Distributes the Program. 25 | 26 | "Licensed Patents" mean patent claims licensable by a Contributor which 27 | are necessarily infringed by the use or sale of its Contribution alone 28 | or when combined with the Program. 29 | 30 | "Program" means the Contributions Distributed in accordance with this 31 | Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement 34 | or any Secondary License (as applicable), including Contributors. 35 | 36 | "Derivative Works" shall mean any work, whether in Source Code or other 37 | form, that is based on (or derived from) the Program and for which the 38 | editorial revisions, annotations, elaborations, or other modifications 39 | represent, as a whole, an original work of authorship. 40 | 41 | "Modified Works" shall mean any work in Source Code or other form that 42 | results from an addition to, deletion from, or modification of the 43 | contents of the Program, including, for purposes of clarity any new file 44 | in Source Code form that contains any contents of the Program. Modified 45 | Works shall not include works that contain only declarations, 46 | interfaces, types, classes, structures, or files of the Program solely 47 | in each case in order to link to, bind by name, or subclass the Program 48 | or Modified Works thereof. 49 | 50 | "Distribute" means the acts of a) distributing or b) making available 51 | in any manner that enables the transfer of a copy. 52 | 53 | "Source Code" means the form of a Program preferred for making 54 | modifications, including but not limited to software source code, 55 | documentation source, and configuration files. 56 | 57 | "Secondary License" means either the GNU General Public License, 58 | Version 2.0, or any later versions of that license, including any 59 | exceptions or additional permissions as identified by the initial 60 | Contributor. 61 | 62 | 2. GRANT OF RIGHTS 63 | 64 | a) Subject to the terms of this Agreement, each Contributor hereby 65 | grants Recipient a non-exclusive, worldwide, royalty-free copyright 66 | license to reproduce, prepare Derivative Works of, publicly display, 67 | publicly perform, Distribute and sublicense the Contribution of such 68 | Contributor, if any, and such Derivative Works. 69 | 70 | b) Subject to the terms of this Agreement, each Contributor hereby 71 | grants Recipient a non-exclusive, worldwide, royalty-free patent 72 | license under Licensed Patents to make, use, sell, offer to sell, 73 | import and otherwise transfer the Contribution of such Contributor, 74 | if any, in Source Code or other form. This patent license shall 75 | apply to the combination of the Contribution and the Program if, at 76 | the time the Contribution is added by the Contributor, such addition 77 | of the Contribution causes such combination to be covered by the 78 | Licensed Patents. The patent license shall not apply to any other 79 | combinations which include the Contribution. No hardware per se is 80 | licensed hereunder. 81 | 82 | c) Recipient understands that although each Contributor grants the 83 | licenses to its Contributions set forth herein, no assurances are 84 | provided by any Contributor that the Program does not infringe the 85 | patent or other intellectual property rights of any other entity. 86 | Each Contributor disclaims any liability to Recipient for claims 87 | brought by any other entity based on infringement of intellectual 88 | property rights or otherwise. As a condition to exercising the 89 | rights and licenses granted hereunder, each Recipient hereby 90 | assumes sole responsibility to secure any other intellectual 91 | property rights needed, if any. For example, if a third party 92 | patent license is required to allow Recipient to Distribute the 93 | Program, it is Recipient's responsibility to acquire that license 94 | before distributing the Program. 95 | 96 | d) Each Contributor represents that to its knowledge it has 97 | sufficient copyright rights in its Contribution, if any, to grant 98 | the copyright license set forth in this Agreement. 99 | 100 | e) Notwithstanding the terms of any Secondary License, no 101 | Contributor makes additional grants to any Recipient (other than 102 | those set forth in this Agreement) as a result of such Recipient's 103 | receipt of the Program under the terms of a Secondary License 104 | (if permitted under the terms of Section 3). 105 | 106 | 3. REQUIREMENTS 107 | 108 | 3.1 If a Contributor Distributes the Program in any form, then: 109 | 110 | a) the Program must also be made available as Source Code, in 111 | accordance with section 3.2, and the Contributor must accompany 112 | the Program with a statement that the Source Code for the Program 113 | is available under this Agreement, and informs Recipients how to 114 | obtain it in a reasonable manner on or through a medium customarily 115 | used for software exchange; and 116 | 117 | b) the Contributor may Distribute the Program under a license 118 | different than this Agreement, provided that such license: 119 | i) effectively disclaims on behalf of all other Contributors all 120 | warranties and conditions, express and implied, including 121 | warranties or conditions of title and non-infringement, and 122 | implied warranties or conditions of merchantability and fitness 123 | for a particular purpose; 124 | 125 | ii) effectively excludes on behalf of all other Contributors all 126 | liability for damages, including direct, indirect, special, 127 | incidental and consequential damages, such as lost profits; 128 | 129 | iii) does not attempt to limit or alter the recipients' rights 130 | in the Source Code under section 3.2; and 131 | 132 | iv) requires any subsequent distribution of the Program by any 133 | party to be under a license that satisfies the requirements 134 | of this section 3. 135 | 136 | 3.2 When the Program is Distributed as Source Code: 137 | 138 | a) it must be made available under this Agreement, or if the 139 | Program (i) is combined with other material in a separate file or 140 | files made available under a Secondary License, and (ii) the initial 141 | Contributor attached to the Source Code the notice described in 142 | Exhibit A of this Agreement, then the Program may be made available 143 | under the terms of such Secondary Licenses, and 144 | 145 | b) a copy of this Agreement must be included with each copy of 146 | the Program. 147 | 148 | 3.3 Contributors may not remove or alter any copyright, patent, 149 | trademark, attribution notices, disclaimers of warranty, or limitations 150 | of liability ("notices") contained within the Program from any copy of 151 | the Program which they Distribute, provided that Contributors may add 152 | their own appropriate notices. 153 | 154 | 4. COMMERCIAL DISTRIBUTION 155 | 156 | Commercial distributors of software may accept certain responsibilities 157 | with respect to end users, business partners and the like. While this 158 | license is intended to facilitate the commercial use of the Program, 159 | the Contributor who includes the Program in a commercial product 160 | offering should do so in a manner which does not create potential 161 | liability for other Contributors. Therefore, if a Contributor includes 162 | the Program in a commercial product offering, such Contributor 163 | ("Commercial Contributor") hereby agrees to defend and indemnify every 164 | other Contributor ("Indemnified Contributor") against any losses, 165 | damages and costs (collectively "Losses") arising from claims, lawsuits 166 | and other legal actions brought by a third party against the Indemnified 167 | Contributor to the extent caused by the acts or omissions of such 168 | Commercial Contributor in connection with its distribution of the Program 169 | in a commercial product offering. The obligations in this section do not 170 | apply to any claims or Losses relating to any actual or alleged 171 | intellectual property infringement. In order to qualify, an Indemnified 172 | Contributor must: a) promptly notify the Commercial Contributor in 173 | writing of such claim, and b) allow the Commercial Contributor to control, 174 | and cooperate with the Commercial Contributor in, the defense and any 175 | related settlement negotiations. The Indemnified Contributor may 176 | participate in any such claim at its own expense. 177 | 178 | For example, a Contributor might include the Program in a commercial 179 | product offering, Product X. That Contributor is then a Commercial 180 | Contributor. If that Commercial Contributor then makes performance 181 | claims, or offers warranties related to Product X, those performance 182 | claims and warranties are such Commercial Contributor's responsibility 183 | alone. Under this section, the Commercial Contributor would have to 184 | defend claims against the other Contributors related to those performance 185 | claims and warranties, and if a court requires any other Contributor to 186 | pay any damages as a result, the Commercial Contributor must pay 187 | those damages. 188 | 189 | 5. NO WARRANTY 190 | 191 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 192 | PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" 193 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 194 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF 195 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 196 | PURPOSE. Each Recipient is solely responsible for determining the 197 | appropriateness of using and distributing the Program and assumes all 198 | risks associated with its exercise of rights under this Agreement, 199 | including but not limited to the risks and costs of program errors, 200 | compliance with applicable laws, damage to or loss of data, programs 201 | or equipment, and unavailability or interruption of operations. 202 | 203 | 6. DISCLAIMER OF LIABILITY 204 | 205 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 206 | PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS 207 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 208 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 209 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 210 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 211 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 212 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE 213 | POSSIBILITY OF SUCH DAMAGES. 214 | 215 | 7. GENERAL 216 | 217 | If any provision of this Agreement is invalid or unenforceable under 218 | applicable law, it shall not affect the validity or enforceability of 219 | the remainder of the terms of this Agreement, and without further 220 | action by the parties hereto, such provision shall be reformed to the 221 | minimum extent necessary to make such provision valid and enforceable. 222 | 223 | If Recipient institutes patent litigation against any entity 224 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 225 | Program itself (excluding combinations of the Program with other software 226 | or hardware) infringes such Recipient's patent(s), then such Recipient's 227 | rights granted under Section 2(b) shall terminate as of the date such 228 | litigation is filed. 229 | 230 | All Recipient's rights under this Agreement shall terminate if it 231 | fails to comply with any of the material terms or conditions of this 232 | Agreement and does not cure such failure in a reasonable period of 233 | time after becoming aware of such noncompliance. If all Recipient's 234 | rights under this Agreement terminate, Recipient agrees to cease use 235 | and distribution of the Program as soon as reasonably practicable. 236 | However, Recipient's obligations under this Agreement and any licenses 237 | granted by Recipient relating to the Program shall continue and survive. 238 | 239 | Everyone is permitted to copy and distribute copies of this Agreement, 240 | but in order to avoid inconsistency the Agreement is copyrighted and 241 | may only be modified in the following manner. The Agreement Steward 242 | reserves the right to publish new versions (including revisions) of 243 | this Agreement from time to time. No one other than the Agreement 244 | Steward has the right to modify this Agreement. The Eclipse Foundation 245 | is the initial Agreement Steward. The Eclipse Foundation may assign the 246 | responsibility to serve as the Agreement Steward to a suitable separate 247 | entity. Each new version of the Agreement will be given a distinguishing 248 | version number. The Program (including Contributions) may always be 249 | Distributed subject to the version of the Agreement under which it was 250 | received. In addition, after a new version of the Agreement is published, 251 | Contributor may elect to Distribute the Program (including its 252 | Contributions) under the new version. 253 | 254 | Except as expressly stated in Sections 2(a) and 2(b) above, Recipient 255 | receives no rights or licenses to the intellectual property of any 256 | Contributor under this Agreement, whether expressly, by implication, 257 | estoppel or otherwise. All rights in the Program not expressly granted 258 | under this Agreement are reserved. Nothing in this Agreement is intended 259 | to be enforceable by any entity that is not a Contributor or Recipient. 260 | No third-party beneficiary rights are created under this Agreement. 261 | 262 | Exhibit A - Form of Secondary Licenses Notice 263 | 264 | "This Source Code may also be made available under the following 265 | Secondary Licenses when the conditions for such availability set forth 266 | in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), 267 | version(s), and exceptions or additional permissions here}." 268 | 269 | Simply including a copy of this Agreement, including this Exhibit A 270 | is not sufficient to license the Source Code under Secondary Licenses. 271 | 272 | If it is not possible or desirable to put the notice in a particular 273 | file, then You may include the notice in a location (such as a LICENSE 274 | file in a relevant directory) where a recipient would be likely to 275 | look for such a notice. 276 | 277 | You may add additional accurate notices of copyright ownership. -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Custom Cypress commands for Theia IDE 2 | 3 | These files (modules in `src` folder) can be used in Theia Automation (e.g., COBOL LS, Debugger for Mainframe, Control 4 | Cobol Flow testing). You can easily import this library into your Cypress project. This library will add new functions 5 | to your test suites for making Theia actions (such as `cy.openFile()`, `cy.goToLine()` etc.). 6 | 7 | #### Prerequisite: 8 | 9 | - Windows Environment 10 | - Linux Environment 11 | 12 | #### Install: 13 | 14 | Inside your Cypress project (project with test suites) run 15 | 16 | ``` 17 | yarn add https://github.com/eclipse/che-che4z.git 18 | ``` 19 | 20 | Add the following line to your global configuration file: 21 | 22 | ```js 23 | // usually cypress/support/index.js 24 | import 'che-che4z/tests'; 25 | ``` 26 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@eclipse/che-che4z", 3 | "version": "0.0.0-development", 4 | "description": "Custom Cypress commands for Theia IDE", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "files": [ 8 | "dist/**/*.js", 9 | "dist/**/*.d.ts" 10 | ], 11 | "scripts": { 12 | "postinstall": "tsc --build tsconfig.json" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/eclipse/che-che4z.git" 17 | }, 18 | "author": "Broadcom", 19 | "license": "EPL-2.0", 20 | "dependencies": { 21 | "typescript": "^4.0.3", 22 | "yarn-lockfile": "^1.1.1" 23 | }, 24 | "devDependencies": { 25 | "@types/node": "^14.14.28", 26 | "@typescript-eslint/eslint-plugin": "^4.5.0", 27 | "@typescript-eslint/parser": "^4.5.0", 28 | "cypress": "^7.0.0", 29 | "cypress-iframe": "^1.0.1", 30 | "cypress-xpath": "^1.6.2", 31 | "eslint": "^7.11.0", 32 | "eslint-config-prettier": "^6.14.0", 33 | "eslint-plugin-cypress": "^2.11.2", 34 | "eslint-plugin-prettier": "^3.1.4", 35 | "husky": "^4.3.0", 36 | "lint-staged": "^10.4.2", 37 | "prettier": "^2.1.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/src/cypressEnv.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | export const USER = Cypress.env('username').replace(/\r?\n|\r/g, ''); 15 | export const PASS = Cypress.env('password').replace(/\r?\n|\r/g, ''); 16 | export const CICSUSER1 = Cypress.env('cicsUser1').replace(/\r?\n|\r/g, ''); 17 | export const CICSPASS1 = Cypress.env('cicsPass1').replace(/\r?\n|\r/g, ''); 18 | export const CICSUSER2 = Cypress.env('cicsUser2').replace(/\r?\n|\r/g, ''); 19 | export const CICSPASS2 = Cypress.env('cicsPass2').replace(/\r?\n|\r/g, ''); 20 | export const ZOWE = Cypress.env('zowe') == true ? true : false; 21 | export const CICSAPPLID = Cypress.env('cicsApplId') ? Cypress.env('cicsApplId').replace(/\r?\n|\r/g, '') : ''; 22 | export const SYMDUMPHOST = Cypress.env('symDumpHost'); 23 | export const SYMDUMPPASSWD = Cypress.env('symDumpPasswd'); 24 | export const SYMDUMPPORT = Cypress.env('symDumpPort'); 25 | export const INTERTESTPORT = Cypress.env('interTestPort') 26 | ? Number(Cypress.env('interTestPort').replace(/\r?\n|\r/g, '')) 27 | : undefined; 28 | export const CONVJCL = Cypress.env('convertedJCL') ? Cypress.env('convertedJCL').replace(/\r?\n|\r/g, '') : undefined; 29 | export const ORIGJCL = Cypress.env('originalJCL') ? Cypress.env('originalJCL').replace(/\r?\n|\r/g, '') : undefined; 30 | -------------------------------------------------------------------------------- /tests/src/debug.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | /* eslint-disable @typescript-eslint/no-namespace */ 16 | 17 | /// 18 | import { Theia, VSCODE } from './selectors'; 19 | import { USER, PASS, CICSAPPLID, INTERTESTPORT, CONVJCL, ORIGJCL } from './cypressEnv'; 20 | 21 | const env = Cypress.env('ide'); 22 | const IDE = env === 'theia' ? Theia : VSCODE; 23 | const rawTypeString = (str: string) => str.replace(/{/g, '{{}'); // Types the literal { key 24 | 25 | declare global { 26 | namespace Cypress { 27 | interface Chainable { 28 | /** 29 | * Read and write JSON file 30 | * Copy from test_files/project/dap/ specific launch json file 31 | * and paste to .theia/launch.json 32 | * @example cy.readAndWriteJsonFile('TEST') 33 | */ 34 | readAndWriteJsonFile(expression: string): Chainable; 35 | } 36 | } 37 | } 38 | Cypress.Commands.add('readAndWriteJsonFile', (expression: string) => { 39 | cy.readFile(`test_files/project/dap/${expression}.launch.json`).then((content) => { 40 | content.configurations[0].interTestUserName = USER; 41 | // @ts-ignore 42 | cy.updateParams(content); 43 | cy.writeFile('test_files/project/.theia/launch.json', content); 44 | cy.writeFile('test_files/project/.vscode/launch.json', content); 45 | }); 46 | }); 47 | 48 | declare global { 49 | namespace Cypress { 50 | interface Chainable { 51 | updateParams(content: any): Chainable; 52 | } 53 | } 54 | } 55 | Cypress.Commands.add('updateParams', (content: any) => { 56 | if (INTERTESTPORT) { 57 | content.configurations[0].interTestPort = INTERTESTPORT; 58 | } 59 | 60 | const type = content.configurations[0].type; 61 | switch (type) { 62 | case 'intertest-cics': 63 | if (CICSAPPLID) { 64 | content.configurations[0].cicsApplId = CICSAPPLID; 65 | } 66 | break; 67 | case 'intertest-batch': 68 | if (CONVJCL) { 69 | content.configurations[0].convertedJCL = CONVJCL; 70 | } 71 | if (ORIGJCL) { 72 | content.configurations[0].originalJCL.inDSN = ORIGJCL; 73 | } 74 | break; 75 | } 76 | }); 77 | 78 | declare global { 79 | namespace Cypress { 80 | interface Chainable { 81 | /** 82 | * Read and write JSON file with Multiuser 83 | * Copy from test_files/project/dap/ specific launch json file 84 | * and paste to .theia/launch.json 85 | * @example cy.readAndWriteJsonFile('MULTIUSER', USER1) 86 | */ 87 | readAndWriteJsonFileMultiuser(expression: string, user: string): Chainable; 88 | } 89 | } 90 | } 91 | Cypress.Commands.add('readAndWriteJsonFileMultiuser', (expression: string, cicsUser: string) => { 92 | cy.readFile(`test_files/project/dap/${expression}.launch.json`).then((content) => { 93 | content.configurations[0].interTestUserName = USER; 94 | content.configurations[0].cicsUserId = cicsUser; 95 | // @ts-ignore 96 | cy.updateParams(content); 97 | cy.writeFile('test_files/project/.theia/launch.json', content); 98 | cy.writeFile('test_files/project/.vscode/launch.json', content); 99 | }); 100 | }); 101 | 102 | declare global { 103 | namespace Cypress { 104 | interface Chainable { 105 | /** 106 | * Press on F1 key 107 | * 108 | * @example cy.F1() 109 | */ 110 | F1(): Chainable; 111 | } 112 | } 113 | } 114 | Cypress.Commands.add('F1', () => { 115 | cy.get(Theia.body).trigger('keydown', { key: 'F1', code: 'F1' }); 116 | }); 117 | 118 | declare global { 119 | namespace Cypress { 120 | interface Chainable { 121 | /** 122 | * Convert JCL with Batch 123 | * 124 | * @example cy.convertJCL() 125 | */ 126 | convertJCL(): Chainable; 127 | } 128 | } 129 | } 130 | Cypress.Commands.add('convertJCL', () => { 131 | //@ts-ignore 132 | cy.F1(); 133 | cy.get(Theia.inputF1).as('quickOpen').type('Batch: Convert JCL').type('{enter}').wait(500); 134 | cy.get('@quickOpen') 135 | .type(PASS, { log: false, delay: 200 }) 136 | .then(($input) => { 137 | if ($input.val() !== PASS) { 138 | throw new Error('Different value of typed password'); 139 | } 140 | }) 141 | .type('{enter}'); 142 | }); 143 | 144 | declare global { 145 | namespace Cypress { 146 | interface Chainable { 147 | /** 148 | * Fetch Extended Sources, specify the PROGRAM name. 149 | * 150 | * @example cy.fetchExtendedSources('TEST.cbl') 151 | */ 152 | fetchExtendedSources(programName: string): Chainable; 153 | } 154 | } 155 | } 156 | Cypress.Commands.add('fetchExtendedSources', (programName: string) => { 157 | cy.task('isFileExists', `test_files/project/.c4z/.extsrcs/${programName}`).then((exists) => { 158 | if (!exists) { 159 | //@ts-ignore 160 | cy.F1(); 161 | cy.get(Theia.inputF1).as('quickOpen').type('Fetch Extended Sources').type('{enter}').wait(500); 162 | cy.get('@quickOpen') 163 | .type(PASS, { log: false, delay: 200 }) 164 | .then(($input) => { 165 | if ($input.val() !== PASS) { 166 | throw new Error('Different value of typed password'); 167 | } 168 | }) 169 | .type('{enter}'); 170 | cy.readFile(`test_files/project/.c4z/.extsrcs/${programName}`); 171 | } else { 172 | cy.openFolder('.c4z/.extsrcs').openFile(`${programName}`); 173 | } 174 | //@ts-ignore 175 | cy.openDapPanel(); 176 | }); 177 | }); 178 | 179 | declare global { 180 | namespace Cypress { 181 | interface Chainable { 182 | /** 183 | * Press on F5 184 | * 185 | * @example cy.F5() 186 | */ 187 | F5(): Chainable; 188 | } 189 | } 190 | } 191 | Cypress.Commands.add('F5', () => { 192 | cy.get(Theia.inputF1).trigger('keydown', { key: 'F5', code: 'F5' }); 193 | }); 194 | 195 | declare global { 196 | namespace Cypress { 197 | interface Chainable { 198 | /** 199 | * Start a debug session without password 200 | * Add a program name to verify it in debug configuration 201 | * 202 | * @example cy.startDebugSession('TEST') 203 | */ 204 | startDebugSession(expression: string): Chainable; 205 | } 206 | } 207 | } 208 | Cypress.Commands.add('startDebugSession', (expression: string) => { 209 | cy.readAndWriteJsonFile(expression); 210 | cy.F5(); 211 | cy.get(Theia.selectDebugConfiguration).contains(expression); 212 | cy.get(Theia.debugMode, { timeout: 50000 }); 213 | }); 214 | 215 | declare global { 216 | namespace Cypress { 217 | interface Chainable { 218 | /** 219 | * Start a debug session with password 220 | * Add a program name to verify it in debug configuration 221 | * 222 | * @example cy.startDebugSessionPassowrd('TEST') 223 | */ 224 | startDebugSessionPassword(expression: string): Chainable; 225 | } 226 | } 227 | } 228 | Cypress.Commands.add('startDebugSessionPassword', (expression: string) => { 229 | cy.readAndWriteJsonFile(expression); 230 | cy.F5(); 231 | cy.get(Theia.inputF1) 232 | .type(PASS, { log: false, delay: 200 }) 233 | .then(($input) => { 234 | if ($input.val() !== PASS) { 235 | throw new Error('Different value of typed password'); 236 | } 237 | }) 238 | .type('{enter}'); 239 | cy.get(Theia.selectDebugConfiguration).contains(expression); 240 | cy.get(Theia.debugMode, { timeout: 50000 }).wait(500); 241 | }); 242 | 243 | declare global { 244 | namespace Cypress { 245 | interface Chainable { 246 | /** 247 | * Start a debug session with password 248 | * Add a program name to verify it in debug configuration 249 | * 250 | * @example cy.startDebugSessionMultiuser('MULTIUSER1', CICSPASS1, CICSUSER1); 251 | */ 252 | startDebugSessionMultiuser(expression: string, pass: string, user: string): Chainable; 253 | } 254 | } 255 | } 256 | Cypress.Commands.add('startDebugSessionMultiuser', (expression: string, cicspass: string, cicsuser: string) => { 257 | cy.readAndWriteJsonFileMultiuser(expression, cicsuser); 258 | cy.openDapPanel(); 259 | cy.clickOnStartDebug(); 260 | cy.get(Theia.inputF1) 261 | .type(PASS, { log: false, delay: 200 }) 262 | .type('{enter}') 263 | .type(cicspass, { log: false, delay: 200 }) 264 | .type('{enter}'); 265 | cy.get(Theia.selectDebugConfiguration).contains(expression); 266 | cy.get(Theia.debugMode, { timeout: 50000 }).wait(500); 267 | }); 268 | 269 | declare global { 270 | namespace Cypress { 271 | interface Chainable { 272 | /** 273 | * Start a debug session with password 274 | * Add a program name to verify it in debug configuration 275 | * 276 | * @example cy.startDebugSessionMultiuser2('MULTIUSER2', CICSPASS2, CICSUSER2); 277 | */ 278 | startDebugSessionMultiuser2(expression: string, pass: string, user: string): Chainable; 279 | } 280 | } 281 | } 282 | Cypress.Commands.add('startDebugSessionMultiuser2', (expression: string, pass: string, cicsuser: string) => { 283 | cy.readAndWriteJsonFileMultiuser(expression, cicsuser); 284 | cy.openDapPanel(); 285 | cy.clickOnStartDebug(); 286 | cy.get(Theia.selectDebugConfiguration).contains(expression); 287 | cy.get(Theia.debugMode, { timeout: 50000 }).wait(500); 288 | }); 289 | 290 | declare global { 291 | namespace Cypress { 292 | interface Chainable { 293 | /** 294 | * Get current line when debugging (i.e. where yellow line appears). 295 | * 296 | * @example cy.getCurrentDebugLineNumber().should('eq', 42) 297 | */ 298 | getCurrentDebugLineNumber(): Chainable; 299 | } 300 | } 301 | } 302 | Cypress.Commands.add('getCurrentDebugLineNumber', () => { 303 | cy.get(Theia.editor) 304 | .not(Theia.modHidden) 305 | .find(Theia.debugHighlightLine) 306 | .parent() 307 | .should('have.css', 'top') 308 | .then((top) => { 309 | cy.get(Theia.editor) 310 | .not(Theia.modHidden) 311 | .find(Theia.lineNumber) 312 | .parent(`[style*="top:${top}"]`) 313 | .invoke('text') 314 | .then(parseFloat); 315 | }); 316 | }); 317 | 318 | declare global { 319 | namespace Cypress { 320 | interface Chainable { 321 | /** 322 | * Put a breakpoint at specific line 323 | * 324 | * @example cy.putBreakpointAtLine(10) 325 | */ 326 | putBreakpointAtLine(lineNumber: number): Chainable; 327 | } 328 | } 329 | } 330 | Cypress.Commands.add('putBreakpointAtLine', (lineNumber: number) => { 331 | const lineNumberRegex = RegExp(`^${lineNumber}$`); 332 | cy.goToLine(lineNumber); 333 | cy.get(Theia.lineNumber).contains(lineNumberRegex).parent().click('left', { force: true }); 334 | cy.get(Theia.lineNumber).contains(lineNumberRegex).parent().find(Theia.debugBreakpont); 335 | }); 336 | 337 | declare global { 338 | namespace Cypress { 339 | interface Chainable { 340 | /** 341 | * Remove a breakpoint at specific line 342 | * 343 | * @example cy.removeBreakpoint(10) 344 | */ 345 | removeBreakpoint(lineNumber: number): Chainable; 346 | } 347 | } 348 | } 349 | Cypress.Commands.add('removeBreakpoint', (lineNumber: number) => { 350 | const lineNumberRegex = RegExp(`^${lineNumber}$`); 351 | cy.get(Theia.lineNumber).contains(lineNumberRegex).parent().find(Theia.debugBreakpont).click(); 352 | cy.get(Theia.lineNumber).contains(lineNumberRegex).parent().find(Theia.debugBreakpont).should('not.exist'); 353 | }); 354 | 355 | declare global { 356 | namespace Cypress { 357 | interface Chainable { 358 | /** 359 | * Edit a breakpoint at specific line 360 | * 361 | * @example cy.editBreakpointExpression(10, "NUMB = p'5'") 362 | */ 363 | editBreakpointExpression(lineNumber: number, expression: string): Chainable; 364 | } 365 | } 366 | } 367 | Cypress.Commands.add('editBreakpointExpression', (lineNumber: number, expression: string) => { 368 | const lineNumberRegex = RegExp(`^${lineNumber}$`); 369 | cy.get(Theia.lineNumber) 370 | .contains(lineNumberRegex) 371 | .parent() 372 | .rightclick('left', { force: true }) 373 | .get(Theia.submenuItemLabel) 374 | .contains('Edit Breakpoint...') 375 | .click(); 376 | cy.get(Theia.debugBreakpointWidget) 377 | .find(Theia.debugBreakpointInput) 378 | .type(`{selectall}{backspace}${expression}`) 379 | .type('{enter}'); 380 | }); 381 | 382 | declare global { 383 | namespace Cypress { 384 | interface Chainable { 385 | /** 386 | * Add aconditional breakpoint at specific line 387 | * 388 | * @example cy.addConditionalBreakpoint(10, "NUMB = p'5'") 389 | */ 390 | addConditionalBreakpoint(lineNumber: number, expression: string): Chainable; 391 | } 392 | } 393 | } 394 | Cypress.Commands.add('addConditionalBreakpoint', (lineNumber: number, expression: string) => { 395 | const lineNumberRegex = RegExp(`^${lineNumber}$`); 396 | cy.get(Theia.lineNumber) 397 | .contains(lineNumberRegex) 398 | .parent() 399 | .rightclick('left', { force: true }) 400 | .get(Theia.submenuItemLabel) 401 | .contains('Add Conditional Breakpoint...') 402 | .click(); 403 | cy.get(Theia.debugBreakpointWidget).find(Theia.debugBreakpointInput).type(expression).type('{enter}'); 404 | }); 405 | 406 | declare global { 407 | namespace Cypress { 408 | interface Chainable { 409 | /** 410 | * Edit a breakpoint at specific line "Hit Count" 411 | * 412 | * @example cy.editBreakpointHitCount(10, "NUMB = p'5'") 413 | */ 414 | editBreakpointHitCount(lineNumber: number, expression: string): Chainable; 415 | } 416 | } 417 | } 418 | Cypress.Commands.add('editBreakpointHitCount', (lineNumber: number, expression: string) => { 419 | const lineNumberRegex = RegExp(`^${lineNumber}$`); 420 | cy.get(Theia.lineNumber) 421 | .contains(lineNumberRegex) 422 | .parent() 423 | .rightclick('left', { force: true }) 424 | .get(Theia.submenuItemLabel) 425 | .contains('Edit Breakpoint...') 426 | .click(); 427 | cy.get(Theia.debugBreakpointSelect).select('Hit Count'); 428 | cy.get(Theia.debugBreakpointWidget).find(Theia.debugBreakpointInput).type(expression).type('{enter}'); 429 | }); 430 | 431 | declare global { 432 | namespace Cypress { 433 | interface Chainable { 434 | /** 435 | * Edit a breakpoint at specific line "Log Message" 436 | * 437 | * @example cy.editBreakpointLogMessage(10, "I am here with FACT: {FACT} and NUM: {NUM}") 438 | */ 439 | editBreakpointLogMessage(lineNumber: number, expression: string): Chainable; 440 | } 441 | } 442 | } 443 | Cypress.Commands.add('editBreakpointLogMessage', (lineNumber: number, expression: string) => { 444 | const lineNumberRegex = RegExp(`^${lineNumber}$`); 445 | cy.get(Theia.lineNumber) 446 | .contains(lineNumberRegex) 447 | .parent() 448 | .rightclick('left', { force: true }) 449 | .get(Theia.submenuItemLabel) 450 | .contains('Edit Breakpoint...') 451 | .click(); 452 | cy.get(Theia.debugBreakpointSelect).select('Log Message'); 453 | cy.get(Theia.debugBreakpointWidget) 454 | .find(Theia.debugBreakpointInput) 455 | .type(rawTypeString(expression), { delay: 100 }) 456 | .type('{enter}'); 457 | }); 458 | 459 | declare global { 460 | namespace Cypress { 461 | interface Chainable { 462 | /** 463 | * Click on 'Continue' 464 | * 465 | * @example cy.clickOnContinue() 466 | */ 467 | clickOnContinue(): Chainable; 468 | } 469 | } 470 | } 471 | Cypress.Commands.add('clickOnContinue', () => { 472 | cy.get(Theia.debugContinue).should('not.have.class', 'theia-mod-disabled').click().click().wait(2000); 473 | }); 474 | 475 | declare global { 476 | namespace Cypress { 477 | interface Chainable { 478 | /** 479 | * Click on 'Start Debugging' 480 | * 481 | * @example cy.clickOnStartDebug() 482 | */ 483 | clickOnStartDebug(): Chainable; 484 | } 485 | } 486 | } 487 | Cypress.Commands.add('clickOnStartDebug', () => { 488 | cy.get(Theia.debugStart).should('not.have.class', 'theia-mod-disabled').click(); 489 | }); 490 | 491 | declare global { 492 | namespace Cypress { 493 | interface Chainable { 494 | /** 495 | * Click on 'Step Over' 496 | * 497 | * @example cy.clickOnStepOver() 498 | */ 499 | clickOnStepOver(): Chainable; 500 | } 501 | } 502 | } 503 | Cypress.Commands.add('clickOnStepOver', () => { 504 | cy.get(Theia.debugStepOver).should('not.have.class', 'theia-mod-disabled').click().click().wait(2000); 505 | }); 506 | 507 | declare global { 508 | namespace Cypress { 509 | interface Chainable { 510 | /** 511 | * Click on 'Step Into' 512 | * 513 | * @example cy.clickOnStepInto() 514 | */ 515 | clickOnStepInto(): Chainable; 516 | } 517 | } 518 | } 519 | Cypress.Commands.add('clickOnStepInto', () => { 520 | cy.get(Theia.debugStepInto).should('not.have.class', 'theia-mod-disabled').click().click().wait(2000); 521 | }); 522 | 523 | declare global { 524 | namespace Cypress { 525 | interface Chainable { 526 | /** 527 | * Click on 'Step Out' 528 | * 529 | * @example cy.clickOnStepOut() 530 | */ 531 | clickOnStepOut(): Chainable; 532 | } 533 | } 534 | } 535 | Cypress.Commands.add('clickOnStepOut', () => { 536 | cy.get(Theia.debugStepOut).should('not.have.class', 'theia-mod-disabled').click().click().wait(2000); 537 | }); 538 | 539 | declare global { 540 | namespace Cypress { 541 | interface Chainable { 542 | /** 543 | * Click on 'Restart' 544 | * 545 | * @example cy.clickOnRestart() 546 | */ 547 | clickOnRestart(): Chainable; 548 | } 549 | } 550 | } 551 | Cypress.Commands.add('clickOnRestart', () => { 552 | cy.get(Theia.debugRestart).should('not.have.class', 'theia-mod-disabled').click().click().wait(2000); 553 | }); 554 | 555 | declare global { 556 | namespace Cypress { 557 | interface Chainable { 558 | /** 559 | * Click on 'Stop' 560 | * 561 | * @example cy.clickOnStop() 562 | */ 563 | clickOnStop(): Chainable; 564 | } 565 | } 566 | } 567 | Cypress.Commands.add('clickOnStop', () => { 568 | cy.get(Theia.debugStop).click({ force: true }); 569 | }); 570 | 571 | declare global { 572 | namespace Cypress { 573 | interface Chainable { 574 | /** 575 | * Open DAP panel. 576 | * 577 | * @example cy.openDapPanel() 578 | */ 579 | openDapPanel(): Chainable; 580 | } 581 | } 582 | } 583 | Cypress.Commands.add('openDapPanel', () => { 584 | cy.get(Theia.leftRightPanel).then(($theia) => { 585 | if ($theia.find(Theia.elementCollapsed).length || $theia.find('#debug.theia-debug-container.p-mod-hidden').length) { 586 | cy.get(Theia.debugIcon).click({ force: true }); 587 | } 588 | }); 589 | }); 590 | 591 | declare global { 592 | namespace Cypress { 593 | interface Chainable { 594 | /** 595 | * Close DAP panel. 596 | * 597 | * @example cy.closeDapPanel() 598 | */ 599 | openDapPanel(): Chainable; 600 | } 601 | } 602 | } 603 | Cypress.Commands.add('closeDapPanel', () => { 604 | cy.get(Theia.debugIcon).click({ force: true }); 605 | }); 606 | 607 | declare global { 608 | namespace Cypress { 609 | interface Chainable { 610 | /** 611 | * Invoke Debug Console. 612 | * 613 | * @example cy.debugConsole().contains('TEST') 614 | */ 615 | debugConsole(): Chainable; 616 | } 617 | } 618 | } 619 | Cypress.Commands.add('debugConsole', () => { 620 | cy.get(Theia.theiaConsole); 621 | }); 622 | 623 | declare global { 624 | namespace Cypress { 625 | interface Chainable { 626 | /** 627 | * Clear Debug Console. 628 | * 629 | * @example cy.clearConsole() 630 | */ 631 | clearConsole(): Chainable; 632 | } 633 | } 634 | } 635 | Cypress.Commands.add('clearConsole', () => { 636 | cy.get(Theia.theiaClearConsole).click({ force: true }); 637 | }); 638 | 639 | declare global { 640 | namespace Cypress { 641 | interface Chainable { 642 | /** 643 | * Remove all breakpoints 644 | * 645 | * @example cy.removeAllBreakpoints() 646 | */ 647 | removeAllBreakpoints(): Chainable; 648 | } 649 | } 650 | } 651 | Cypress.Commands.add('removeAllBreakpoints', () => { 652 | cy.get(Theia.debugBreakpointsView).trigger('mousedown').click(); 653 | cy.get(Theia.debugRemoveAllBreakpoint).click({ force: true }); 654 | }); 655 | 656 | declare global { 657 | namespace Cypress { 658 | interface Chainable { 659 | /** 660 | * Change variables value 661 | * 662 | * @example cy.changeVariableValue('NUMB', 5) 663 | */ 664 | changeVariableValue(variable: string, numb: number): Chainable; 665 | } 666 | } 667 | } 668 | Cypress.Commands.add('changeVariableValue', (variable, numb) => { 669 | cy.get(Theia.debugVariablesPanel).as('variablePanel'); 670 | cy.get('@variablePanel').click(); 671 | cy.get('@variablePanel').contains('Locals').click().wait(500); 672 | cy.get('@variablePanel').contains(variable).dblclick(); 673 | cy.get(Theia.dialogContent).find('.theia-input').type(numb).type('{enter}'); 674 | }); 675 | 676 | declare global { 677 | namespace Cypress { 678 | interface Chainable { 679 | /** 680 | * Change variables value 681 | * 682 | * @example cy.changeVariableValueSecondLevel('TASK-STRUCTURE', 'TASKNUM', '5'); 683 | */ 684 | changeVariableValue(folder: string, variable: string, numb: number): Chainable; 685 | } 686 | } 687 | } 688 | Cypress.Commands.add('changeVariableValueSecondLevel', (folder, variable, numb) => { 689 | cy.get(Theia.debugVariablesPanel).as('variablePanel'); 690 | cy.get('@variablePanel').click(); 691 | cy.get('@variablePanel').contains('Locals').click().wait(500); 692 | cy.get('@variablePanel').contains(folder).click().wait(500); 693 | cy.get('@variablePanel').contains(variable).dblclick(); 694 | cy.get(Theia.dialogContent).find('.theia-input').type(numb).type('{enter}'); 695 | }); 696 | declare global { 697 | namespace Cypress { 698 | interface Chainable { 699 | /** 700 | * Check variables value 701 | * 702 | * @example cy.checkVariableValue('NUMB', 5) 703 | */ 704 | //@ts-ignore 705 | checkVariableValue(variable: string, numb: number): Chainable; 706 | } 707 | } 708 | } 709 | Cypress.Commands.add('checkVariableValue', (variable, numb) => { 710 | cy.get(Theia.debugVariablesPanel).as('variablePanel'); 711 | cy.get('@variablePanel').click(); 712 | cy.get('@variablePanel').contains('Locals').click().wait(500); 713 | cy.get(Theia.consoleVariable + ' ' + `[title="${variable}"]`) 714 | .siblings() 715 | .contains(numb); 716 | }); 717 | 718 | declare global { 719 | namespace Cypress { 720 | interface Chainable { 721 | /** 722 | * Check variables value 723 | * 724 | * @example cy.checkVariableValueSecondLevel('TEST-1', 'COMP-CODE', 5); 725 | */ 726 | checkVariableValueSecondLevel(var1: string, var2: string, numb: number): Chainable; 727 | } 728 | } 729 | } 730 | Cypress.Commands.add('checkVariableValueSecondLevel', (var1, var2, numb) => { 731 | cy.get(Theia.debugVariablesPanel).as('variablePanel'); 732 | cy.get('@variablePanel').click(); 733 | cy.get('@variablePanel').contains('Locals').wait(500); 734 | cy.get('@variablePanel').contains(var1).click().wait(500); 735 | cy.get(Theia.consoleVariable + ' ' + `[title="${var2}"]`) 736 | .siblings() 737 | .should('contain', numb); 738 | }); 739 | 740 | declare global { 741 | namespace Cypress { 742 | interface Chainable { 743 | /** 744 | * Run /trace command in debug console 745 | * 746 | * @example cy.theiaTrace() 747 | */ 748 | theiaTrace(): Chainable; 749 | } 750 | } 751 | } 752 | Cypress.Commands.add('theiaTrace', () => { 753 | cy.get(Theia.theiConsoleInput).type('/trace{enter}'); 754 | }); 755 | 756 | declare global { 757 | namespace Cypress { 758 | interface Chainable { 759 | /** 760 | * Gain output from debug comsole after running some debug command 761 | * 762 | * @example cy.debugExpressionOutput('foobar') 763 | */ 764 | debugExpressionOutput(text: string): Chainable; 765 | } 766 | } 767 | } 768 | Cypress.Commands.add('debugExpressionOutput', (text) => { 769 | cy.get(Theia.debugConsloleExpression).contains(text); 770 | }); 771 | 772 | declare global { 773 | namespace Cypress { 774 | interface Chainable { 775 | /** 776 | * Run /trace off command in debug console 777 | * 778 | * @example cy.traceOff() 779 | */ 780 | traceOff(): Chainable; 781 | } 782 | } 783 | } 784 | Cypress.Commands.add('traceOff', () => { 785 | cy.get(Theia.theiConsoleInput).type('/trace off{enter}'); 786 | }); 787 | 788 | declare global { 789 | namespace Cypress { 790 | interface Chainable { 791 | /** 792 | * Run /trace on command in debug console 793 | * 794 | * @example cy.traceOn() 795 | */ 796 | traceOn(): Chainable; 797 | } 798 | } 799 | } 800 | Cypress.Commands.add('traceOn', () => { 801 | cy.get(Theia.theiConsoleInput).type('/trace on{enter}'); 802 | }); 803 | 804 | declare global { 805 | namespace Cypress { 806 | interface Chainable { 807 | /** 808 | * Run /calltrace on command in debug console 809 | * 810 | * @example cy.callTraceOn() 811 | */ 812 | callTraceOn(): Chainable; 813 | } 814 | } 815 | } 816 | Cypress.Commands.add('callTraceOn', () => { 817 | cy.get(Theia.theiConsoleInput).type('/calltrace on{enter}'); 818 | }); 819 | 820 | declare global { 821 | namespace Cypress { 822 | interface Chainable { 823 | /** 824 | * Run /calltrace off command in debug console 825 | * 826 | * @example cy.callTraceOff() 827 | */ 828 | callTraceOff(): Chainable; 829 | } 830 | } 831 | } 832 | Cypress.Commands.add('callTraceOff', () => { 833 | cy.get(Theia.theiConsoleInput).type('/calltrace off{enter}'); 834 | }); 835 | 836 | declare global { 837 | namespace Cypress { 838 | interface Chainable { 839 | /** 840 | * Retrieve the call trace info 841 | * 842 | * @example cy.callTraceItem('SOME_PROGRAM:22') 843 | */ 844 | callTraceItem(callTraceName: string): Chainable; 845 | } 846 | } 847 | } 848 | Cypress.Commands.add('callTraceItem', (callTraceName) => { 849 | cy.get(Theia.debugFrames).as('variablePanel').contains(callTraceName); 850 | }); 851 | 852 | declare global { 853 | namespace Cypress { 854 | interface Chainable { 855 | /** 856 | * Fetch multiple sources 857 | * 858 | * @example cy.fetchMultipleSources( 859 | 'Extended source for PROGRAM1 was fetched successfully.', 860 | 'Extended source for PROGRAM2 was fetched successfully.', 861 | ); 862 | */ 863 | fetchMultipleSources(message: string): Chainable; 864 | } 865 | } 866 | } 867 | Cypress.Commands.add('fetchMultipleSources', (popups) => { 868 | cy.F1(); 869 | cy.get(Theia.inputF1).as('quickOpen').type('Fetch Extended Sources').type('{enter}').wait(500); 870 | cy.get('@quickOpen') 871 | .type(PASS, { log: false, delay: 200 }) 872 | .then(($input) => { 873 | if ($input.val() !== PASS) { 874 | throw new Error('Different value of typed password'); 875 | } 876 | }) 877 | .type('{enter}'); 878 | cy.get(Theia.notificationList).should(($content) => { 879 | [popups].forEach((message) => { 880 | expect($content).to.contain.text(message); 881 | }); 882 | }); 883 | }); 884 | 885 | declare global { 886 | namespace Cypress { 887 | interface Chainable { 888 | /** 889 | * Expand View for statement trace data 890 | * 891 | * @example cy.expandStatementTrace(); 892 | */ 893 | expandStatementTrace(): Chainable; 894 | } 895 | } 896 | } 897 | Cypress.Commands.add('expandStatementTrace', () => { 898 | cy.get(Theia.debugStatementTrace).click(); 899 | }); 900 | 901 | declare global { 902 | namespace Cypress { 903 | interface Chainable { 904 | /** 905 | * View for statement trace data 906 | * 907 | * @example cy.statementTrace('DECUPGMB:23 IF NUMB = 0 DECUPGMB:22 MOVE NUMB TO NUM.'); 908 | */ 909 | statementTrace(statementTraceName: string): Chainable; 910 | } 911 | } 912 | } 913 | Cypress.Commands.add('statementTrace', (statementTraceName) => { 914 | cy.get(Theia.debugStatementTrace).contains(statementTraceName); 915 | }); 916 | -------------------------------------------------------------------------------- /tests/src/e4e.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | /* eslint-disable @typescript-eslint/no-namespace */ 16 | 17 | /// 18 | 19 | import { USER, PASS } from './cypressEnv'; 20 | import { Theia, E4E } from './selectors'; 21 | 22 | declare global { 23 | /** 24 | * A workaround that has allowed me to add import and export 25 | * statements to my *.ts files is to explicitly declare 26 | * Cypress on the global namespace. 27 | */ 28 | namespace Cypress { 29 | interface Chainable { 30 | /** 31 | * Click on the E4E icon 32 | * 33 | * @example cy.openEndevorPanel(); 34 | */ 35 | openEndevorPanel(): Chainable; 36 | } 37 | } 38 | } 39 | Cypress.Commands.add('openEndevorPanel', () => { 40 | cy.get(E4E.explorerContainer).eq(0).click(); 41 | }); 42 | 43 | declare global { 44 | namespace Cypress { 45 | interface Chainable { 46 | /** 47 | * Add a new connection (profile) 48 | * 49 | * @example cy.createNewConnection(); 50 | */ 51 | createNewConnection(): Chainable; 52 | } 53 | } 54 | } 55 | Cypress.Commands.add('createNewConnection', () => { 56 | cy.get(E4E.elmTreeView).contains('Add a New Profile').click(); 57 | }); 58 | 59 | declare global { 60 | namespace Cypress { 61 | interface Chainable { 62 | /** 63 | * Unock the report 64 | * 65 | * @example cy.deleteProfile(ASTRO); 66 | */ 67 | deleteProfile(profileName: string): Chainable; 68 | } 69 | } 70 | } 71 | Cypress.Commands.add('deleteProfile', (profileName) => { 72 | cy.openEndevorPanel().wait(1500); 73 | cy.get(E4E.pluginView).then(($connection) => { 74 | if ($connection.find(`[id="/1:${profileName}"]`).length) { 75 | cy.get(`[title="${profileName}"]`).rightclick(); 76 | cy.get(E4E.hideServise).click(); 77 | cy.wait(2000); 78 | } else { 79 | console.log('Nothing to delete'); 80 | } 81 | }); 82 | }); 83 | 84 | declare global { 85 | namespace Cypress { 86 | interface Chainable { 87 | /** 88 | * Adds a new connection 89 | * 90 | * @example cy.E4EAddNewConnection(ASTRO); 91 | */ 92 | E4EAddNewConnection(profileName: string, host: string): Chainable; 93 | } 94 | } 95 | } 96 | Cypress.Commands.add('E4EAddNewConnection', (profileName, host) => { 97 | cy.createNewConnection(); 98 | cy.get('.monaco-quick-open-widget .quick-open-tree').then(($profilePallete) => { 99 | console.log($profilePallete); 100 | if ($profilePallete.find(`[aria-label="${profileName}, picker"]`).length) { 101 | cy.entryField().type(profileName).type('{enter}'); 102 | } else { 103 | cy.entryField().as('quickOpen').type('{enter}').type(profileName).type('{enter}'); 104 | cy.get('@quickOpen').type(host).type('{enter}').wait(500); 105 | cy.get('@quickOpen').type(USER).type('{enter}').wait(500); 106 | cy.get('@quickOpen').type(PASS, { log: false, delay: 200 }).type('{enter}'); 107 | cy.get('@quickOpen').type('False{enter}'); 108 | cy.wait(500).get(`[title="${profileName}"]`); 109 | } 110 | }); 111 | }); 112 | 113 | declare global { 114 | namespace Cypress { 115 | interface Chainable { 116 | /** 117 | * Get the connection(profile name) 118 | * 119 | * @example cy.connectionNameE4E(Chodov); 120 | */ 121 | connectionNameE4E(profileName: string): Chainable; 122 | } 123 | } 124 | } 125 | Cypress.Commands.add('connectionNameE4E', (profileName) => { 126 | cy.get(`[id="/0:${profileName}"]`); 127 | }); 128 | 129 | declare global { 130 | namespace Cypress { 131 | interface Chainable { 132 | /** 133 | * Click on the connection name(profile) 134 | * 135 | * @example cy.clickOnConnectionNameE4E(TEST.REPORT.EXAMPLE); 136 | */ 137 | clickOnConnectionNameE4E(profileName: string): Chainable; 138 | } 139 | } 140 | } 141 | Cypress.Commands.add('clickOnConnectionNameE4E', (profileName) => { 142 | cy.connectionNameE4E(profileName).trigger('mousedown').click(); 143 | }); 144 | 145 | declare global { 146 | namespace Cypress { 147 | interface Chainable { 148 | /** 149 | * Delete E4E connection 150 | * 151 | * @example cy.deleteE4EConnection(TEST.REPORT.EXAMPLE); 152 | */ 153 | deleteE4EConnection(profileName: string): Chainable; 154 | } 155 | } 156 | } 157 | Cypress.Commands.add('deleteE4EConnection', (profileName) => { 158 | cy.openEndevorPanel(); 159 | cy.get(E4E.endevorExplorer); 160 | cy.get(E4E.endevorExplorer); 161 | cy.clickOnConnectionNameE4E(profileName); 162 | cy.get('[title*="Remove Profile"]').click(); 163 | }); 164 | 165 | declare global { 166 | namespace Cypress { 167 | interface Chainable { 168 | /** 169 | * Add a new configuration 170 | * 171 | * @example cy.addNewConfig(TEST.REPORT.EXAMPLE); 172 | */ 173 | addNewConfig(config: string, profileName: string): Chainable; 174 | } 175 | } 176 | } 177 | Cypress.Commands.add('addNewConfig', (config, profileName) => { 178 | cy.get(`[id="/1:${profileName}"]`).trigger('mousedown').click(); 179 | cy.get('[title*="Add a New Location Profile"]').click(); 180 | cy.get(Theia.openTree).contains(config).click(); 181 | }); 182 | 183 | declare global { 184 | namespace Cypress { 185 | interface Chainable { 186 | /** 187 | * Browse the element within the tree 188 | * 189 | * @example cy.browseElement(PROFILE, FOLDER, SUBFODLER, SUB-SUBFOLDER, PROGRAM); 190 | */ 191 | browseElement(config: string, lvl1: string, lvl2: string, lvl3: string, program: string): Chainable; 192 | } 193 | } 194 | } 195 | Cypress.Commands.add('browseElement', (config, lvl1, lvl2, lvl3, program) => { 196 | cy.get(`[title="${config}"]`).click(); 197 | cy.get(`[title="${lvl1}"]`).click(); 198 | cy.get(`[title="${lvl2}"]`).click(); 199 | cy.get(`[title="${lvl3}"]`).click(); 200 | cy.get(`[title="/${config}/SMPLPROD/2/${lvl1}/${lvl2}/${lvl3}"]`).contains(program); 201 | }); 202 | 203 | declare global { 204 | namespace Cypress { 205 | interface Chainable { 206 | /** 207 | * Click on the element(e.g., COBOL program) 208 | * 209 | * @example cy.openElement(PROFILE, FOLDER, SUBFODLER, SUB-SUBFOLDER, PROGRAM); 210 | */ 211 | openElement(config: string, lvl1: string, lvl2: string, lvl3: string, program: string): Chainable; 212 | } 213 | } 214 | } 215 | Cypress.Commands.add('openElement', (config, lvl1, lvl2, lvl3, program) => { 216 | cy.get(`[title="${config}"]`).click(); 217 | cy.get(`[title="${lvl1}"]`).click(); 218 | cy.get(`[title="${lvl2}"]`).click(); 219 | cy.get(`[title="${lvl3}"]`).click(); 220 | cy.get(`[title="/${config}/SMPLPROD/2/${lvl1}/${lvl2}/${lvl3}"]`).contains(program).click(); 221 | cy.getCurrentTab().contains(`${program}.cobol`); 222 | }); 223 | 224 | declare global { 225 | namespace Cypress { 226 | interface Chainable { 227 | /** 228 | * Click on Edit the element 229 | * 230 | * @example cy.editElement(PROFILE, FOLDER, SUBFODLER, SUB-SUBFOLDER, PROGRAM); 231 | */ 232 | editElement(config: string, lvl1: string, lvl2: string, lvl3: string, program: string): Chainable; 233 | } 234 | } 235 | } 236 | Cypress.Commands.add('editElement', (config, lvl1, lvl2, lvl3, program) => { 237 | cy.get(`[title="/${config}/SMPLPROD/2/${lvl1}/${lvl2}/${lvl3}"]`).contains(program).rightclick(); 238 | cy.get(E4E.editElement).click(); 239 | }); 240 | 241 | declare global { 242 | namespace Cypress { 243 | interface Chainable { 244 | /** 245 | * Click on Retrieve Element With Dependencies 246 | * 247 | * @example cy.retrieveElementWithDependencies(PROFILE, FOLDER, SUBFODLER, SUB-SUBFOLDER, PROGRAM);; 248 | */ 249 | retrieveElementWithDependencies( 250 | config: string, 251 | lvl1: string, 252 | lvl2: string, 253 | lvl3: string, 254 | program: string, 255 | ): Chainable; 256 | } 257 | } 258 | } 259 | Cypress.Commands.add('retrieveElementWithDependencies', (config, lvl1, lvl2, lvl3, program) => { 260 | cy.get(`[title="/${config}/SMPLPROD/2/${lvl1}/${lvl2}/${lvl3}"]`).contains(program).rightclick(); 261 | cy.get(E4E.retrieveElementWithDependencies).click(); 262 | }); 263 | -------------------------------------------------------------------------------- /tests/src/flow.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | /// 16 | // eslint-disable-next-line @typescript-eslint/triple-slash-reference 17 | /// 18 | 19 | /** 20 | * THIS MODULE IS NOT VALID ANYMORE. WE NEED TO USE PLAYWRIGHT IN ORDER 21 | * TO USE IFRAMES IN TESTS. CYPRESS CAN'T HANLDE THEM! 22 | * SOON THIS FILE WOULD BE DELETED. 23 | */ 24 | require('cypress-iframe'); 25 | require('cypress-xpath'); 26 | 27 | /* eslint-disable @typescript-eslint/no-namespace */ 28 | 29 | declare namespace Cypress { 30 | interface Chainable { 31 | /** 32 | * Custom iframe command. For some reason iframe() doesn't work. 33 | * 34 | * @example cy.iframeCustom() 35 | */ 36 | iframeCustom(): Chainable; 37 | } 38 | } 39 | Cypress.Commands.add('iframeCustom', { prevSubject: 'element' }, ($iframe) => { 40 | return new Cypress.Promise((resolve) => { 41 | $iframe.ready(function () { 42 | resolve($iframe.contents().find('body')); 43 | }); 44 | }); 45 | }); 46 | 47 | declare namespace Cypress { 48 | interface Chainable { 49 | /** 50 | * Load nested iframes for Cobol Control Flow 51 | * 52 | * @example cy.loadFlowIframe() 53 | */ 54 | loadFlowIframe(): Chainable; 55 | } 56 | } 57 | Cypress.Commands.add('loadFlowIframe', () => { 58 | //@ts-ignore 59 | cy.frameLoaded('iframe.webview').iframeCustom().find('iframe#active-frame').iframeCustom(); 60 | }); 61 | declare namespace Cypress { 62 | interface Chainable { 63 | /** 64 | * Generates Cobol Control Flow 65 | * 66 | * @example cy.generateCobolControlFlow('s.cbl', '100-Print-User'); 67 | */ 68 | generateCobolControlFlow(): Chainable; 69 | } 70 | } 71 | Cypress.Commands.add('generateCobolControlFlow', (filename: string, paragraph: string) => { 72 | const xpath_paragraph = `//*[name()="g"]//div[@class="node-foreign-object-div-nodeInfo-name selected"][text()="${paragraph}"]`; 73 | cy.get('#theia-main-content-panel .theia-editor').wait(500).rightclick().wait(1000); // wait for onClickListeneres to be set 74 | cy.get('.p-Widget.p-Menu').find('[data-command="__plugin.menu.action.extension.run_parser"]').click(); 75 | cy.get('.theia-notification-list').contains(`Loading control flow of ${filename}`); 76 | //@ts-ignore 77 | cy.loadFlowIframe().xpath(xpath_paragraph); 78 | }); 79 | 80 | declare namespace Cypress { 81 | interface Chainable { 82 | /** 83 | * Generates Cobol Control Flow and click on element 84 | * 85 | * @example cy.generateAndClickCobolControlFlow('s.cbl', '100-Print-User'); 86 | */ 87 | generateAndClickCobolControlFlow(): Chainable; 88 | } 89 | } 90 | Cypress.Commands.add('generateAndClickCobolControlFlow', (filename: string, paragraph: string) => { 91 | const xpath_paragraph = `//*[name()="g"]//div[@class="node-foreign-object-div-nodeInfo-name selected"][text()="${paragraph}"]`; 92 | cy.get('#theia-main-content-panel .theia-editor').wait(500).rightclick().wait(1000); // wait for onClickListeneres to be set 93 | cy.get('.p-Widget.p-Menu').find('[data-command="__plugin.menu.action.extension.run_parser"]').click(); 94 | cy.get('.theia-notification-list').contains(`Loading control flow of ${filename}`); 95 | //@ts-ignore 96 | cy.loadFlowIframe() 97 | //@ts-ignore 98 | .xpath('//*[name()="svg"][@class="svg-chart-container"]') 99 | .click() 100 | .xpath(xpath_paragraph + '/../..') 101 | .click({ force: true }); 102 | }); 103 | -------------------------------------------------------------------------------- /tests/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | import './theiaActions'; 16 | import './languageSupport'; 17 | import './cypressEnv'; 18 | import './debug'; 19 | import './flow'; 20 | import './zowe'; 21 | import './symdump'; 22 | import './selectors'; 23 | -------------------------------------------------------------------------------- /tests/src/languageSupport.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | /* eslint-disable @typescript-eslint/no-namespace */ 15 | 16 | /// 17 | 18 | import { Theia, COBOLLS } from './selectors'; 19 | 20 | declare global { 21 | /** 22 | * A workaround that has allowed me to add import and export 23 | * statements to my *.ts files is to explicitly declare 24 | * Cypress on the global namespace. 25 | */ 26 | namespace Cypress { 27 | interface Chainable { 28 | /** 29 | * Open Output window, select LSP extension and return its output. 30 | * 31 | * @example cy.getLSPOutput().should('have.text', loaded) 32 | */ 33 | getLSPOutput(): Chainable; 34 | } 35 | } 36 | } 37 | Cypress.Commands.add('getLSPOutput', () => { 38 | cy.get(Theia.bottomSplitPanel).then(($theia) => { 39 | if (!$theia.find(Theia.outlineView).length) { 40 | cy.get('.editor-scrollable').type('{shift}{ctrl}u'); 41 | cy.get(Theia.loadSpinner).should('not.exist', { timeout: 40000 }); 42 | } 43 | cy.get(Theia.outputChannelList).select('LSP extension for COBOL language', { timeout: 40000 }); 44 | cy.get(Theia.outputContents); 45 | }); 46 | }); 47 | 48 | declare global { 49 | namespace Cypress { 50 | interface Chainable { 51 | /** 52 | * Click on 'Change Settings' 53 | * 54 | * @example cy.clickOnChangeSettings(A.cpy). 55 | */ 56 | clickOnChangeSettings(copybookName: string): Chainable; 57 | } 58 | } 59 | } 60 | Cypress.Commands.add('clickOnChangeSettings', (copybookName: string) => { 61 | cy.get(Theia.notificationsContainer) 62 | .filter('.open') 63 | .find(Theia.notificationMessage) 64 | .should('contain.text', `Missing copybooks: ${copybookName}`) 65 | .then(($message) => { 66 | cy.wrap($message).parentsUntil(Theia.notification).find(Theia.changeSettingsButton).click(); 67 | }); 68 | }); 69 | 70 | declare global { 71 | namespace Cypress { 72 | interface Chainable { 73 | /** 74 | * Click on 'Add Local Copybboks' 75 | * 76 | * @example cy.addCopybookLocal(A.cpy). 77 | */ 78 | addCopybookLocal(copybookName: string): Chainable; 79 | } 80 | } 81 | } 82 | Cypress.Commands.add('addCopybookLocal', (copybookName: string) => { 83 | cy.get(COBOLLS.inputCopybookNameInSettingsLocal).type(copybookName); 84 | cy.get(COBOLLS.addCopybookInSettingsLocal).click(); 85 | cy.get(COBOLLS.checkCopybookInSettingsLocal).contains(copybookName); 86 | }); 87 | 88 | declare global { 89 | namespace Cypress { 90 | interface Chainable { 91 | /** 92 | * Click on 'Add Copybook DSN' 93 | * 94 | * @example cy.addCopybookDSN(TEST). 95 | */ 96 | addCopybookDSN(DSN: string): Chainable; 97 | } 98 | } 99 | } 100 | Cypress.Commands.add('addCopybookDSN', (DSN: string) => { 101 | cy.get(COBOLLS.inputCopybookNameInSettingsDSN).type(DSN); 102 | cy.get(COBOLLS.addCopybookInSettingsDNS).click(); 103 | cy.get(COBOLLS.checkCopybookInSettingsDSN).contains(DSN); 104 | }); 105 | 106 | declare global { 107 | namespace Cypress { 108 | interface Chainable { 109 | /** 110 | * Click on 'Add Copybook PROFILE' 111 | * 112 | * @example cy.addCopybookProfile(TEST). 113 | */ 114 | addCopybookProfile(ProfileName: string): Chainable; 115 | } 116 | } 117 | } 118 | Cypress.Commands.add('addCopybookProfile', (ProfileName: string) => { 119 | cy.get(COBOLLS.inputProfileInSettings).type(ProfileName).type('{enter}'); 120 | cy.get(COBOLLS.inputProfileInSettings).should('have.value', ProfileName); 121 | }); 122 | 123 | declare global { 124 | namespace Cypress { 125 | interface Chainable { 126 | /** 127 | * Click on 'Workspace Tab' 128 | * 129 | * @example cy.clickWorkspaceTab(). 130 | */ 131 | clickWorkspaceTab(): Chainable; 132 | } 133 | } 134 | } 135 | Cypress.Commands.add('clickWorkspaceTab', () => { 136 | cy.get(Theia.workspaceTabInSettings).contains('Workspace').click(); 137 | }); 138 | 139 | declare global { 140 | namespace Cypress { 141 | interface Chainable { 142 | /** 143 | * Delete Local Copybook in UI 144 | * 145 | * @example cy.deleteCopybookLocal('A.cpy'). 146 | */ 147 | deleteCopybookLocal(copybookName: string): Chainable; 148 | } 149 | } 150 | } 151 | Cypress.Commands.add('deleteCopybookLocal', (copybookName: string) => { 152 | cy.get(COBOLLS.pathsLocalEditor).find(Theia.clearItem).click({ multiple: true }); 153 | }); 154 | 155 | declare global { 156 | namespace Cypress { 157 | interface Chainable { 158 | /** 159 | * Delete DSN in UI 160 | * 161 | * @example cy.deleteCopybookDSN('TEST'). 162 | */ 163 | deleteCopybookDSN(DSN: string): Chainable; 164 | } 165 | } 166 | } 167 | Cypress.Commands.add('deleteCopybookDSN', (DSN: string) => { 168 | cy.get(COBOLLS.pathsDsnEditor).find(Theia.clearItem).click(); 169 | }); 170 | -------------------------------------------------------------------------------- /tests/src/selectors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | export const Theia = { 16 | addValueSettings: '.preference-array-element', 17 | body: 'body', 18 | bottomContentPanel: '#theia-bottom-content-panel', 19 | bottomSplitPanel: '#theia-bottom-split-panel', 20 | changeSettingsButton: '.theia-button[data-action="Change settings"]', 21 | clearItem: '.preference-array-clear-item', 22 | closeButton: '.fa.fa-times.closeButton', 23 | collapsed: '.theia-mod-collapsed', 24 | consoleVariable: '.theia-debug-console-variable', 25 | currentLine: '.current-line', 26 | currentTab: '#theia-main-content-panel .theia-app-main .p-TabBar-content .p-TabBar-tab.p-mod-current', 27 | debugBreakpointHint: '.codicon.theia-debug-breakpoint-hint', 28 | debugBreakpointInput: '.theia-debug-breakpoint-input', 29 | debugBreakpointSelect: '.theia-debug-breakpoint-select select', 30 | debugBreakpointWidget: '.zone-widget-container.theia-debug-breakpoint-widget', 31 | debugBreakpointsView: '[id*="debug:view-container"][id*="debug:breakpoints"]', 32 | debugBreakpont: '.codicon.theia-debug-breakpoint', 33 | debugConsloleExpression: '.theia-debug-console-expression', 34 | debugConsoleVariable: '.theia-debug-console-variable', 35 | debugContinue: '[id^="debug:toolbar"] .debug-action.theia-debug-continue', 36 | debugFrames: '[id*="debug:view-container"][id*="debug:frames"]', 37 | debugHighlightLine: '.theia-debug-top-stack-frame-line', 38 | debugIcon: '#shell-tab-debug', 39 | debugMode: 'body.theia-mod-debugging', 40 | debugRemoveAllBreakpoint: '#debug\\.breakpoint\\.removeAll', 41 | debugRestart: '[id^="debug:toolbar"] .debug-action.theia-debug-restart', 42 | debugStart: '[id^="debug"] .debug-action.theia-debug-start', 43 | debugStatementTrace: '[id*="debug:view-container"][id*="plugin-view:statementTrace"]', 44 | debugStepInto: '[id^="debug:toolbar"] .debug-action.theia-debug-step-into', 45 | debugStepOut: '[id^="debug:toolbar"] .debug-action.theia-debug-step-out', 46 | debugStepOver: '[id^="debug:toolbar"] .debug-action.theia-debug-step-over', 47 | debugStop: '[id^="debug:toolbar"] .debug-action.theia-debug-stop', 48 | debugVariablesPanel: '[id*="debug:view-container"][id*="debug:variables"]', 49 | dialogContent: '.dialogContent', 50 | dialogControl: '.dialogControl', 51 | dialogInput: 'div.dialogBlock input.theia-input', 52 | dialogTitle: '.dialogTitle', 53 | documentation: '.monaco-scrollable-element .docs', 54 | editor: '.theia-editor', 55 | editorError: '.squiggly-error', 56 | editorInfo: '.squiggly-info', 57 | editorWarn: '.squiggly-warning', 58 | elementCollapsed: '#theia-left-content-panel.theia-mod-collapsed', 59 | explorerIcon: 'ul.p-TabBar-content li#shell-tab-explorer-view-container', 60 | explorerId: '#explorer-view-container.p-mod-hidden', 61 | explorerView: '#explorer-view-container--files #files div.theia-TreeNodeContent', 62 | formatDocument: '[data-command="editor.action.formatDocument"]', 63 | goToDefinition: '[data-command="editor.action.revealDefinition"]', 64 | goToReference: '[data-command="editor.action.goToReferences"]', 65 | hoverOverContent: 'div.monaco-editor-hover-content', 66 | inputF1: '.quick-open-input input', 67 | langFeatures: '.pref-content-container.array', 68 | languageMode: '.right.area .hasCommand[title="Select Language Mode"]', 69 | leftRightPanel: '#theia-left-right-split-panel', 70 | lineContent: '.view-line', 71 | lineNumber: '.line-numbers', 72 | linesContent: '.view-lines', 73 | loadSpinner: '.left.area .element .fa-spin', 74 | mainContentPanel: '#theia-main-content-panel', 75 | menuBar: '[id="theia:menubar"]', 76 | menuBarContent: '.p-MenuBar-content', 77 | menuContent: '.p-Menu-content', 78 | modCurrent: 'p-mod-current', 79 | modHidden: '.p-mod-hidden', 80 | modToggled: 'p-mod-toggled', 81 | notification: 'theia-notification-list-item', 82 | notificationList: '.theia-notification-list', 83 | notificationMessage: '.theia-notification-message', 84 | notificationsContainer: '.theia-notifications-container', 85 | openTree: '.quick-open-tree', 86 | outlineView: '#outline-view', 87 | outlineViewTab: '#shell-tab-outline-view', 88 | outputChannelList: '#outputChannelList', 89 | outputContents: '#outputContents', 90 | peekViewWidget: '.peekview-widget .monaco-editor', 91 | popUpMsg: '.theia-notification-list-item-content', 92 | preLoad: 'div.theia-preload', 93 | quickFix: '.action span[title^="Quick Fix"]', 94 | referenceWidget: '.zone-widget', 95 | searchSettings: 'input.settings-search-input.theia-input', 96 | selectDebugConfiguration: '.theia-select.debug-configuration', 97 | slidePanelTitile: '.theia-sidepanel-title', 98 | subMenu: '[data-type="submenu"]', 99 | submenuItemLabel: '.p-Menu-itemLabel', 100 | suggestWidget: '[widgetid="editor.widget.suggestWidget"]', 101 | symbolHighlight: '.view-overlays .symbolHighlight', 102 | tabBar: '.p-TabBar', 103 | tabCloseButton: '.p-TabBar-tabCloseIcon', 104 | tabOpened: '[id^="shell-tab-code-editor-opener"]', 105 | theiConsoleInput: '.p-Widget .theia-console-input', 106 | theiaButton: 'theia-button', 107 | theiaButtonDontSave: '.theia-button.secondary', 108 | theiaButtonOK: '.theia-button.main', 109 | theiaClearConsole: '#debug\\.console\\.clear', 110 | theiaConsole: '.theia-console-ansi-console-item', 111 | treeContainer: '.theia-TreeContainer', 112 | treeNodeSegment: '.theia-TreeNodeSegment', 113 | treeViewDescription: '.theia-tree-view-description', 114 | typeALineNumber: 'input[title^="Type a line number"]', 115 | viewRulers: '.view-rulers', 116 | widgetMenu: '.p-Widget.p-Menu', 117 | workspaceTabInSettings: '.p-TabBar-tab.preferences-scope-tab', 118 | zoneWidget: '.zone-widget', 119 | }; 120 | 121 | export const VSCODE = { 122 | button: '.monaco-button.monaco-text-button', 123 | buttonDontSave: '[title="Don\'t Save"]', 124 | currentLine: '.current-line', 125 | currentTab: '.tabs-container .tab', 126 | dialogContent: '.dialog-message-text', 127 | dialogControl: '.dialog-buttons-row', 128 | dialogInput: 'div.dialogBlock input.theia-input', 129 | documentation: '.monaco-scrollable-element .docs', 130 | editorError: '.squiggly-error', 131 | editorInfo: '.squiggly-info', 132 | editorWarn: '.squiggly-warning', 133 | elementCollapsed: '.menubar.compact.inactive', 134 | explorerIcon: '.action-label.codicon.codicon-explorer-view-icon', 135 | explorerView: '.part.sidebar.left', 136 | formatDocument: '[data-command="editor.action.formatDocument"]', 137 | goToDefinition: '[data-command="editor.action.revealDefinition"]', 138 | hoverOverContent: 'div.monaco-hover-content', 139 | inputF1: '.quick-input-box', 140 | languageMode: '[id="status.editor.mode"]', 141 | leftRightPanel: '.split-view-container', 142 | lineContent: '.view-line', 143 | lineNumber: '.line-numbers', 144 | linesContent: '.view-lines', 145 | mainContentPanel: 'body', 146 | modCurrent: '.expanded', 147 | openTree: '.quick-input-message', 148 | outLine: '[title="Outline"]', 149 | outlineMsg: '.outline-message', 150 | outlineView: '.outline-pane', 151 | outlineViewTab: '[aria-label="Outline Section"]', 152 | peekViewWidget: '.peekview-widget .monaco-editor', 153 | popUpMsg: '.notification-toast-container', 154 | preLoad: '', 155 | suggestWidget: '[widgetid="editor.widget.suggestWidget"]', 156 | tabCloseButton: '[title="Close (Ctrl+F4)"]', 157 | tabOpened: '[id^="shell-tab-code-editor-opener"]', 158 | theiaButtonOK: '.dialog-buttons [title="OK"]', 159 | treeContainer: '.pane-body.outline-pane', 160 | treeNodeSegment: '.theia-TreeNodeSegment', 161 | typeALineNumber: '.quick-input-box', 162 | }; 163 | 164 | export const COBOLLS = { 165 | addCopybookInSettingsDNS: '#cobol-lsp\\.cpy-manager\\.paths-dsn-editor .preference-array-element-btn.add-btn', 166 | addCopybookInSettingsLocal: '#cobol-lsp\\.cpy-manager\\.paths-local-editor .preference-array-element-btn.add-btn', 167 | checkCopybookInSettingsDSN: '#cobol-lsp\\.cpy-manager\\.paths-dsn-editor .preference-array-element-val', 168 | checkCopybookInSettingsLocal: '#cobol-lsp\\.cpy-manager\\.paths-local-editor .pref-input', 169 | inputCopybookNameInSettingsDSN: '#cobol-lsp\\.cpy-manager\\.paths-dsn-editor .preference-array-input', 170 | inputCopybookNameInSettingsLocal: '#cobol-lsp\\.cpy-manager\\.paths-local-editor .preference-array-input', 171 | inputProfileInSettings: 'input[data-preference-id="cobol-lsp.cpy-manager.profiles"]', 172 | pathsDsnEditor: '#cobol-lsp\\.cpy-manager\\.paths-dsn-editor', 173 | pathsLocalEditor: '#cobol-lsp\\.cpy-manager\\.paths-local-editor', 174 | profilesEditor: '#cobol-lsp\\.cpy-manager\\.profiles-editor', 175 | }; 176 | 177 | export const AA4MF_Theia = { 178 | addDataset: '[title*="Add dataset"]', 179 | addProtsym: '[data-command="__plugin.menu.action.symdump.addProtsym:0"]', 180 | deleteConnection: '[data-command="__plugin.menu.action.symdump.deleteConnection"]', 181 | deleteDataset: '[data-command="__plugin.menu.action.symdump.deleteDataset"]', 182 | deletereport: '[data-command*="__plugin.menu.action.symdump.deleteReport"]', 183 | displayGlobalOptions: '[data-command="__plugin.menu.action.symdump.displayGlobalOptions"]', 184 | displayProtdmpOptions: '[data-command="__plugin.menu.action.symdump.displayProtdmpOptions"]', 185 | displayReportOptions: '[data-command="__plugin.menu.action.symdump.displayReportOptions"]', 186 | editConnection: '[data-command*="__plugin.menu.action.symdump.editConnection"]', 187 | editDataset: '[data-command="__plugin.menu.action.symdump.editDataset"]', 188 | filterReports: '[data-command="__plugin.menu.action.symdump.filterDumps:0"]', 189 | filterReportsCancel: '[data-command="__plugin.menu.action.symdump.filterDumpsCancel:0"]', 190 | loadReports: '[data-command="__plugin.menu.action.symdump.loadDumps"]', 191 | lockReport: '[data-command="__plugin.menu.action.symdump.lockReport"]', 192 | newConnection: '[id="__plugin-view-container:symdumpView_title:__plugin.view.title.action.symdump.newConnection"]', 193 | sortReports: '[data-command="__plugin.menu.action.symdump.sortDumps"]', 194 | sortreportAscending: '[data-command="__plugin.menu.action.symdump.sortDumpsAscending"]', 195 | sortreportDescending: '[data-command="__plugin.menu.action.symdump.sortDumpsDescending"]', 196 | symdumpId: '[id="symdump"]', 197 | symdumpJob: '[id="Job=${jobName}${param}"]', 198 | symdumpPanel: '[id="plugin-view-container:symdumpView"]', 199 | symdumpView: 'ul.p-TabBar-content li[id="shell-tab-plugin-view-container:symdumpView"]', 200 | treeView: '.noWrapInfoTree', 201 | unlockReport: '[data-command="__plugin.menu.action.symdump.unlockReport"', 202 | viewLabel: '[data-pref-id="symdump.view.label"]', 203 | viewLabelEditor: '[id="symdump.view.label-editor"]', 204 | }; 205 | 206 | export const AA4MF_VSC = { 207 | addProtsym: '[aria-label="Add PROTSYM"]', 208 | deleteConnection: '[aria-label="Delete connection"]', 209 | deleteDataset: '[data-command="__plugin.menu.action.symdump.deleteDataset"]', 210 | editConnection: '[aria-label="Edit connection"]', 211 | filterReports: '[data-command="__plugin.menu.action.symdump.filterDumps:0"]', 212 | filterReportsCancel: '[data-command="__plugin.menu.action.symdump.filterDumpsCancel:0"]', 213 | loadReports: '[aria-label="Load reports"]', 214 | lockReport: '[data-command="__plugin.menu.action.symdump.lockReport"]', 215 | newConnection: '[class="composite title"] [title="New connection"]', 216 | sortReports: '[data-command="__plugin.menu.action.symdump.sortDumps"]', 217 | sortreportAscending: '[aria-label="Sort by date ascending"]', 218 | sortreportDescending: '[aria-label="Sort by date descending"]', 219 | symdumpId: '[id="workbench.view.extension.symdumpView"]', 220 | symdumpPanel: 221 | '[class="monaco-list list_id_2 mouse-support selection-none"][aria-label="Abend Analyzer for Mainframe"]', 222 | symdumpView: 223 | '[class="action-label activity-workbench-view-extension-symdumpView-6c0515efe99f6c70d438a22c4fc76790ac0e15fb"]', 224 | treeView: '[id="list_id_2_0"]', 225 | unlockReport: '[data-command="__plugin.menu.action.symdump.unlockReport"]', 226 | }; 227 | 228 | export const E4E = { 229 | editElement: '[data-command="__plugin.menu.action.e4e.editElement"]', 230 | elmTreeView: '[id="plugin-view:e4e.elmTreeView"]', 231 | endevorExplorer: '[id="plugin-view:endevorExplorer"]', 232 | explorerContainer: '.p-TabBar-tab[id="shell-tab-plugin-view-container:e4eExplorerContainer"]', 233 | hideServise: '[data-command="__plugin.menu.action.e4e.hideService"]', 234 | pluginView: '[id="plugin-view-container:e4eExplorerContainer--plugin-view:e4e.elmTreeView"]', 235 | retrieveElementWithDependencies: '[data-command="__plugin.menu.action.e4e.retrieveElementWithDependencies"]', 236 | }; 237 | 238 | export const ZOWE = { 239 | addSession: '#__plugin\\.view\\.title\\.action\\.zowe\\.addSession', 240 | deleteProfile: '[data-command*="__plugin.menu.action.zowe.deleteProfile"]', 241 | zoweHidden: '#plugin-view-container\\:zowe.p-mod-hidden', 242 | zoweJobs: '[id*="plugin-view-container:zowe--plugin-view:zowe.jobs"]', 243 | zowePluginView: '[id*="plugin-view-container:zowe"][id*="plugin-view:zowe.explorer"]', 244 | zoweTreeContainer: '[id*="plugin-view:zowe.explorer"] .theia-TreeContainer', 245 | zoweView: '.p-TabBar-content #shell-tab-plugin-view-container\\:zowe', 246 | }; 247 | -------------------------------------------------------------------------------- /tests/src/symdump.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | /* eslint-disable @typescript-eslint/no-namespace */ 16 | 17 | /// 18 | 19 | import { USER, PASS, SYMDUMPHOST, SYMDUMPPASSWD, SYMDUMPPORT } from './cypressEnv'; 20 | import { Theia, VSCODE, AA4MF_Theia, AA4MF_VSC } from './selectors'; 21 | 22 | const env = Cypress.env('ide'); 23 | const IDE = env === 'theia' ? Theia : VSCODE; 24 | const AA4MF = env === 'theia' ? AA4MF_Theia : AA4MF_VSC; 25 | 26 | declare global { 27 | /** 28 | * A workaround that has allowed me to add import and export 29 | * statements to my *.ts files is to explicitly declare 30 | * Cypress on the global namespace. 31 | */ 32 | namespace Cypress { 33 | interface Chainable { 34 | /** 35 | * Add new connection (by clicking on + icon) 36 | * 37 | * @example cy.newConnection() 38 | */ 39 | newConnection(): Chainable; 40 | } 41 | } 42 | } 43 | Cypress.Commands.add('newConnection', () => { 44 | cy.get(AA4MF.newConnection).click({ force: true }); 45 | }); 46 | 47 | declare global { 48 | namespace Cypress { 49 | interface Chainable { 50 | /** 51 | * Find the input field (e.g. adding the profile name, url:port, id and passwd) 52 | * 53 | * @example cy.entryField() 54 | */ 55 | entryField(): Chainable; 56 | } 57 | } 58 | } 59 | Cypress.Commands.add('entryField', () => { 60 | cy.get(IDE.inputF1); 61 | }); 62 | 63 | declare global { 64 | namespace Cypress { 65 | interface Chainable { 66 | /** 67 | * Check the message in the popup page 68 | * 69 | * @example cy.validationMsg('Enter a valid Symdump URL'); 70 | */ 71 | validationMsg(message: string): Chainable; 72 | } 73 | } 74 | } 75 | Cypress.Commands.add('validationMsg', (message) => { 76 | cy.get(IDE.openTree).contains(message); 77 | }); 78 | 79 | declare global { 80 | namespace Cypress { 81 | interface Chainable { 82 | /** 83 | * Click on SymDump icon to open it 84 | * 85 | * @example cy.openSymDump(); 86 | */ 87 | openSymDump(): Chainable; 88 | } 89 | } 90 | } 91 | Cypress.Commands.add('openSymDump', () => { 92 | cy.get(AA4MF.symdumpView).click(); 93 | }); 94 | 95 | declare global { 96 | namespace Cypress { 97 | interface Chainable { 98 | /** 99 | * Find SymDump panel 100 | * 101 | * @example cy.symDumpPanel(); 102 | */ 103 | symDumpPanel(): Chainable; 104 | } 105 | } 106 | } 107 | Cypress.Commands.add('symDumpPanel', () => { 108 | cy.get(AA4MF.symdumpPanel); 109 | }); 110 | 111 | declare global { 112 | namespace Cypress { 113 | interface Chainable { 114 | /** 115 | * Add new connection (putting profile name, host, port and password) 116 | * 117 | * @example cy.symDumpAddNewConnection('TEST'); 118 | */ 119 | symDumpAddNewConnection(profileName: string): Chainable; 120 | } 121 | } 122 | } 123 | Cypress.Commands.add('symDumpAddNewConnection', (profileName) => { 124 | cy.newConnection(); 125 | cy.entryField() 126 | .as('quickOpen') 127 | .type(profileName, { delay: 50 }) 128 | .type('{enter}') 129 | .wait(500) 130 | .type(`${SYMDUMPHOST}:${SYMDUMPPORT}`, { delay: 50 }); 131 | cy.get('@quickOpen').type(USER, { delay: 50 }).type('{enter}'); 132 | cy.get('@quickOpen').type(SYMDUMPPASSWD, { log: false, delay: 50 }); 133 | cy.connectionName(profileName); 134 | }); 135 | 136 | declare global { 137 | namespace Cypress { 138 | interface Chainable { 139 | /** 140 | * Get the connection name 141 | * 142 | * @example cy.connectionName('TEST'); 143 | */ 144 | connectionName(profileName: string): Chainable; 145 | } 146 | } 147 | } 148 | Cypress.Commands.add('connectionName', (profileName) => { 149 | cy.get(AA4MF.treeView).contains(profileName); 150 | }); 151 | 152 | declare global { 153 | namespace Cypress { 154 | interface Chainable { 155 | /** 156 | * Click on the connection name 157 | * 158 | * @example cy.clickOnConnectionName('TEST'); 159 | */ 160 | clickOnConnectionName(profileName: string): Chainable; 161 | } 162 | } 163 | } 164 | Cypress.Commands.add('clickOnConnectionName', (profileName) => { 165 | cy.connectionName(profileName).click(); 166 | }); 167 | 168 | declare global { 169 | namespace Cypress { 170 | interface Chainable { 171 | /** 172 | * Delete the connection, data (host and port) are taken from your as-a file 173 | * 174 | * @example cy.deleteSymDumpConnectionDefault('TEST'); 175 | */ 176 | deleteSymDumpConnectionDefault(profileName: string): Chainable; 177 | } 178 | } 179 | } 180 | Cypress.Commands.add('deleteSymDumpConnectionDefault', (profileName) => { 181 | if (IDE === Theia) { 182 | cy.openSymDump().wait(1000); 183 | cy.get(AA4MF.symdumpId).then(($connection) => { 184 | if ($connection.find(`[id="/0:${profileName}"]`).length) { 185 | cy.symDumpPanel().type('{pageup}').type('{pageup}'); 186 | cy.clickOnConnectionName(profileName).rightclick(); 187 | cy.get(AA4MF.deleteConnection).click(); 188 | cy.get(Theia.dialogControl) 189 | .find('button' + IDE.theiaButtonOK) 190 | .contains('OK') 191 | .click({ force: true }); 192 | } else { 193 | console.log('Nothing to delete'); 194 | } 195 | }); 196 | } else { 197 | cy.get(AA4MF.symdumpId) 198 | .wait(5000) 199 | .then(($connection) => { 200 | if ($connection.find('[id="list_id_2_0"]').length) { 201 | // cy.symDumpPanel().type('{pageup}').type('{pageup}'); 202 | cy.clickOnConnectionName(profileName).rightclick(); 203 | cy.get(AA4MF.deleteConnection).click(); 204 | cy.get(IDE.theiaButtonOK).click({ force: true }); 205 | } else { 206 | console.log('Nothing to delete'); 207 | } 208 | }); 209 | } 210 | }); 211 | 212 | declare global { 213 | namespace Cypress { 214 | interface Chainable { 215 | /** 216 | * Delete the connection by adding custom hostname and port 217 | * 218 | * @example cy.deleteSymDumpConnectionCustom('TEST'); 219 | */ 220 | deleteSymDumpConnectionCustom(host: string, port: number): Chainable; 221 | } 222 | } 223 | } 224 | Cypress.Commands.add('deleteSymDumpConnectionCustom', (host, port) => { 225 | cy.openSymDump(); 226 | cy.get(AA4MF.symdumpId).then(($connection) => { 227 | if ($connection.find(Theia.treeContainer + '.empty').length) { 228 | console.log('Nothing to delete'); 229 | } else { 230 | cy.symDumpPanel().type('{pageup}').type('{pageup}'); 231 | cy.get(`[title*= "${host}:${port}"]`).trigger('mousedown').click(); 232 | cy.get(AA4MF.deleteConnection).click(); 233 | cy.get(Theia.dialogControl) 234 | .find('button' + Theia.theiaButtonOK) 235 | .contains('OK') 236 | .click({ force: true }); 237 | } 238 | }); 239 | }); 240 | 241 | declare global { 242 | namespace Cypress { 243 | interface Chainable { 244 | /** 245 | * Add a Data Set 246 | * 247 | * @example cy.addDataSet('CDE.PROD.CAWORLD.PRTLIB', 'TEST'); 248 | */ 249 | addDataSet(DSNAME: string, profileName: string, type: string): Chainable; 250 | } 251 | } 252 | } 253 | Cypress.Commands.add('addDataSet', (DSNAME, profileName, type) => { 254 | cy.clickOnConnectionName(profileName); 255 | cy.get('[title*="Add dataset"]').click(); 256 | cy.entryField().type(DSNAME, { delay: 50 }).type('{enter}').type(type, { delay: 50 }).type('{enter}'); 257 | }); 258 | 259 | declare global { 260 | namespace Cypress { 261 | interface Chainable { 262 | /** 263 | * Get the Data Set ID 264 | * 265 | * @example cy.dataSet('CDE.PROD.CAWORLD.PRTLIB').click(); 266 | */ 267 | dataSet(DSNAME: string): Chainable; 268 | } 269 | } 270 | } 271 | Cypress.Commands.add('dataSet', (DSNAME) => { 272 | if (IDE === Theia) { 273 | cy.get(Theia.treeNodeSegment + `[title*="${DSNAME}"]`); 274 | } else { 275 | cy.get('[id="list_id_2_2"]'); 276 | } 277 | }); 278 | 279 | declare global { 280 | namespace Cypress { 281 | interface Chainable { 282 | /** 283 | * Load reports 284 | * 285 | * @example cy.jobDump(jobName).click().get('[title*="Load dump"]').click(); 286 | */ 287 | jobDump(jobName: string): Chainable; 288 | } 289 | } 290 | } 291 | Cypress.Commands.add('jobDump', (jobName) => { 292 | if (IDE === Theia) { 293 | cy.get(`[title*="Job=${jobName}"]`); 294 | } else { 295 | cy.get(`[aria-label*="Job=${jobName}"]`); 296 | } 297 | }); 298 | 299 | declare global { 300 | namespace Cypress { 301 | interface Chainable { 302 | /** 303 | * Click on Load Dumps 304 | * 305 | * @example cy.loadDumps('CDE.PROD.CAWORLD.PRTLIB'); 306 | */ 307 | loadDumps(DSNAME: string): Chainable; 308 | } 309 | } 310 | } 311 | Cypress.Commands.add('loadDumps', (DSNAME) => { 312 | cy.dataSet(DSNAME).trigger('mousedown').click(); 313 | }); 314 | 315 | declare global { 316 | namespace Cypress { 317 | interface Chainable { 318 | /** 319 | * Click on Load Dump 320 | * 321 | * @example cy.loadDump('CDE.PROD.CAWORLD.PRTLIB'); 322 | */ 323 | loadDump(DSNAME: string): Chainable; 324 | } 325 | } 326 | } 327 | Cypress.Commands.add('loadDump', (DSNAME) => { 328 | cy.dataSet(DSNAME).trigger('mousedown').click(); 329 | }); 330 | 331 | declare global { 332 | namespace Cypress { 333 | interface Chainable { 334 | /** 335 | * Click on Load Dump and check missing pop-up message 336 | * 337 | * @example cy.missingDumpMessage('Error: TTException:Invalid mainframe user credentials.'); 338 | */ 339 | missingDumpMessage(message: string): Chainable; 340 | } 341 | } 342 | } 343 | Cypress.Commands.add('missingDumpMessage', (message) => { 344 | cy.get(IDE.popUpMsg).should('contain', message); 345 | }); 346 | 347 | declare global { 348 | namespace Cypress { 349 | interface Chainable { 350 | /** 351 | * Get Job's id 352 | * 353 | * @example cy.jobInTree(); 354 | */ 355 | jobInTree(jobName: string): Chainable; 356 | } 357 | } 358 | } 359 | Cypress.Commands.add('jobInTree', (jobName) => { 360 | cy.get(`[title*="Job=${jobName}"]`); 361 | }); 362 | 363 | declare global { 364 | namespace Cypress { 365 | interface Chainable { 366 | /** 367 | * Click on Job 368 | * 369 | * @example cy.clickOnJob("DAVSC01A CA32:S=0C7 2018/10/04 15.37"); 370 | */ 371 | clickOnJob(jobName: string): Chainable; 372 | } 373 | } 374 | } 375 | Cypress.Commands.add('clickOnJob', (jobName) => { 376 | cy.jobInTree(jobName).click({ force: true }); 377 | }); 378 | 379 | declare global { 380 | namespace Cypress { 381 | interface Chainable { 382 | /** 383 | * Get Job's id 384 | * 385 | * @example cy.findDump(jobName, param); 386 | */ 387 | findDump(jobName: string, param: string): Chainable; 388 | } 389 | } 390 | } 391 | Cypress.Commands.add('findDump', (jobName, param) => { 392 | cy.window().then(() => { 393 | cy.get(`[id="Job=${jobName}${param}"]`); 394 | }); 395 | }); 396 | 397 | declare global { 398 | namespace Cypress { 399 | interface Chainable { 400 | /** 401 | * Click on found Dump 402 | * 403 | * @example cy.clickOnDump(dataSet, jobName, param); 404 | */ 405 | clickOnDump(jobName: string, param: string): Chainable; 406 | } 407 | } 408 | } 409 | Cypress.Commands.add('clickOnDump', (jobName, param) => { 410 | cy.window().then(() => { 411 | cy.findDump(jobName, param).click({ force: true }); 412 | }); 413 | }); 414 | 415 | declare global { 416 | namespace Cypress { 417 | interface Chainable { 418 | /** 419 | * Click on icon 'Edit connection' 420 | * 421 | * @example cy.editConnection('TEST'); 422 | */ 423 | editConnection(profileName: string): Chainable; 424 | } 425 | } 426 | } 427 | Cypress.Commands.add('editConnection', (profileName) => { 428 | cy.clickOnConnectionName(profileName).rightclick(); 429 | cy.get(AA4MF.editConnection).click(); 430 | }); 431 | 432 | declare global { 433 | namespace Cypress { 434 | interface Chainable { 435 | /** 436 | * Edit a SymDump hostname 437 | * 438 | * @example cy.editConnection('http://1.2.3.4:19567', 'TEST'); 439 | */ 440 | editConnection(host: string, profileName: string): Chainable; 441 | } 442 | } 443 | } 444 | Cypress.Commands.add('editConnectionHost', (host, profileName) => { 445 | cy.editConnection(profileName); 446 | cy.entryField() 447 | .type('{enter}', { delay: 1000 }) 448 | .type('{selectall}{backspace}') 449 | .type(`${host}{enter}`) 450 | .type('{enter}', { delay: 1000 }) 451 | .type('{enter}', { delay: 1000 }); 452 | }); 453 | 454 | declare global { 455 | namespace Cypress { 456 | interface Chainable { 457 | /** 458 | * Edit a SymDump port 459 | * 460 | * @example cy.editConnectionPort('http://10.23.33.232:12345', 'TEST'); 461 | */ 462 | editConnectionPort(port: string, profileName: string): Chainable; 463 | } 464 | } 465 | } 466 | Cypress.Commands.add('editConnectionPort', (port, profileName) => { 467 | cy.editConnection(profileName); 468 | cy.entryField() 469 | .type('{enter}') 470 | .type('{selectall}{backspace}') 471 | .type(port) 472 | .type('{enter}', { delay: 200 }) 473 | .type('{enter}', { delay: 200 }); 474 | }); 475 | 476 | declare global { 477 | namespace Cypress { 478 | interface Chainable { 479 | /** 480 | * Edit a SymDump username 481 | * 482 | * @example cy.editConnectionUsername('username1', 'TEST'); 483 | */ 484 | editConnectionUsername(user: string, profileName: string): Chainable; 485 | } 486 | } 487 | } 488 | Cypress.Commands.add('editConnectionUsername', (user, profileName) => { 489 | cy.editConnection(profileName); 490 | cy.entryField() 491 | .type('{enter}') 492 | .type('{enter}') 493 | .type('{selectall}{backspace}') 494 | .type(user) 495 | .type('{enter}', { delay: 200 }) 496 | .type(PASS, { log: false, delay: 200 }) 497 | .type('{enter}'); 498 | }); 499 | 500 | declare global { 501 | namespace Cypress { 502 | interface Chainable { 503 | /** 504 | * While edititng in fact no data has been changed 505 | * 506 | * @example cy.editConnectionNothing('TEST'); 507 | */ 508 | editConnectionNothing(profileName: string): Chainable; 509 | } 510 | } 511 | } 512 | Cypress.Commands.add('editConnectionNothing', (profileName) => { 513 | cy.editConnection(profileName); 514 | cy.entryField().type('{enter}').type('{enter}').type('{enter}').type('{enter}'); 515 | }); 516 | 517 | declare global { 518 | namespace Cypress { 519 | interface Chainable { 520 | /** 521 | * Sort dumps by ascending 522 | * 523 | * @example cy.sortDumpsAscending(); 524 | */ 525 | sortDumpsAscending(): Chainable; 526 | } 527 | } 528 | } 529 | Cypress.Commands.add('sortDumpsAscending', () => { 530 | cy.get(AA4MF.sortreportAscending).click().wait(500); 531 | }); 532 | 533 | declare global { 534 | namespace Cypress { 535 | interface Chainable { 536 | /** 537 | * Sort dumps by descending 538 | * 539 | * @example cy.sortDumpsDescending(); 540 | */ 541 | sortDumpsDescending(): Chainable; 542 | } 543 | } 544 | } 545 | Cypress.Commands.add('sortDumpsDescending', () => { 546 | cy.get(AA4MF.sortreportDescending).click().wait(500); 547 | }); 548 | 549 | declare global { 550 | namespace Cypress { 551 | interface Chainable { 552 | /** 553 | * Open SymDump settings 554 | * 555 | * @example cy.openSettingsSymDump(); 556 | */ 557 | openSettingsSymDump(): Chainable; 558 | } 559 | } 560 | } 561 | Cypress.Commands.add('openSettingsSymDump', () => { 562 | if (IDE === Theia) { 563 | cy.get(Theia.menuBar).get(Theia.menuBarContent).contains('File').click(); 564 | cy.get('[data-type="submenu"]').click(); 565 | cy.get('.p-Menu-itemLabel').contains('Open Preferences').click(); 566 | cy.get('input.settings-search-input.theia-input').type('symdump'); 567 | } else { 568 | cy.get('body').type('{ctrl},'); 569 | cy.get('[data-mode-id="plaintext"]').type('symdump'); 570 | } 571 | }); 572 | 573 | declare global { 574 | namespace Cypress { 575 | interface Chainable { 576 | /** 577 | * Get the PROTSYM element 578 | * 579 | * @example cy.PROTSYM(); 580 | */ 581 | PROTSYM(): Chainable; 582 | } 583 | } 584 | } 585 | Cypress.Commands.add('PROTSYM', () => { 586 | if (IDE === Theia) { 587 | cy.get('[title*="PROTSYMS"]'); 588 | } else { 589 | cy.get('#list_id_2_1'); 590 | } 591 | }); 592 | 593 | declare global { 594 | namespace Cypress { 595 | interface Chainable { 596 | /** 597 | * Add a PROTSYM 598 | * 599 | * @example cy.addProtsym('TEST1'); 600 | */ 601 | addProtsym(protsym: string): Chainable; 602 | } 603 | } 604 | } 605 | Cypress.Commands.add('addProtsym', (protsym) => { 606 | if (IDE === Theia) { 607 | cy.PROTSYM().trigger('mousedown').click(); 608 | cy.get('[title*="Add PROTSYM"]').click(); 609 | cy.entryField().type(`${protsym}{enter}`); 610 | cy.get(`[title*="${protsym}"]`); 611 | } else { 612 | cy.PROTSYM().trigger('mousedown').click(); 613 | cy.get('[title*="Add PROTSYM"]').click(); 614 | cy.entryField().type(`${protsym}{enter}`); 615 | cy.PROTSYM().click(); 616 | cy.get(`[aria-label*="${protsym}"]`); 617 | } 618 | }); 619 | 620 | declare global { 621 | namespace Cypress { 622 | interface Chainable { 623 | /** 624 | * Add a PROTSYM 625 | * 626 | * @example cy.addProtsymRightClick('TEST2'); 627 | */ 628 | addProtsymRightClick(protsym: string): Chainable; 629 | } 630 | } 631 | } 632 | Cypress.Commands.add('addProtsymRightClick', (protsym) => { 633 | cy.PROTSYM().rightclick(); 634 | cy.get(AA4MF.addProtsym).contains('Add PROTSYM').click(); 635 | cy.entryField().type(`${protsym}{enter}`); 636 | if (IDE === Theia) { 637 | cy.get(`[title*="${protsym}"]`); 638 | } else { 639 | cy.get('[id="list_id_2_3"]').contains(protsym); 640 | } 641 | }); 642 | 643 | declare global { 644 | namespace Cypress { 645 | interface Chainable { 646 | /** 647 | * Load dumps with right-click on a DS 648 | * 649 | * @example cy.loadDumpsRightClick('QWERTY.UIO.LOAD); 650 | */ 651 | loadDumpsRightClick(dataSet: string): Chainable; 652 | } 653 | } 654 | } 655 | Cypress.Commands.add('loadDumpsRightClick', (dataSet) => { 656 | cy.dataSet(dataSet).rightclick(); 657 | cy.get(AA4MF.loadReports).click(); 658 | }); 659 | 660 | declare global { 661 | namespace Cypress { 662 | interface Chainable { 663 | /** 664 | * Delete DS right-click on a DS 665 | * 666 | * @example cy.deleteDSRightClick('QWERTY.UIO.LOAD'); 667 | */ 668 | deleteDSRightClick(dataSet: string): Chainable; 669 | } 670 | } 671 | } 672 | Cypress.Commands.add('deleteDSRightClick', (dataSet) => { 673 | cy.dataSet(dataSet).rightclick(); 674 | cy.get(AA4MF.deleteDataset).click(); 675 | cy.get(Theia.dialogControl) 676 | .find('button' + Theia.theiaButtonOK) 677 | .contains('OK') 678 | .click({ force: true }); 679 | }); 680 | 681 | declare global { 682 | namespace Cypress { 683 | interface Chainable { 684 | /** 685 | * Delete DS right-click on a DS 686 | * 687 | * @example cy.openFilterPallete('QWERTY.UIO.LOAD'); 688 | */ 689 | openFilterPallete(dataSet: string): Chainable; 690 | } 691 | } 692 | } 693 | Cypress.Commands.add('openFilterPallete', (dataSet) => { 694 | cy.dataSet(dataSet).rightclick(); 695 | cy.get(AA4MF.filterReports).click(); 696 | }); 697 | 698 | declare global { 699 | namespace Cypress { 700 | interface Chainable { 701 | /** 702 | * Find cancel filter icon 703 | * 704 | * @example cy.cancelFilter(); 705 | */ 706 | cancelFilter(): Chainable; 707 | } 708 | } 709 | } 710 | Cypress.Commands.add('cancelFilter', () => { 711 | cy.get(AA4MF.filterReportsCancel); 712 | }); 713 | 714 | declare global { 715 | namespace Cypress { 716 | interface Chainable { 717 | /** 718 | * Open sorting pallete 719 | * 720 | * @example cy.openSortPallete(); 721 | */ 722 | openSortPallete(): Chainable; 723 | } 724 | } 725 | } 726 | Cypress.Commands.add('openSortPallete', () => { 727 | cy.get(AA4MF.sortReports); 728 | }); 729 | 730 | declare global { 731 | namespace Cypress { 732 | interface Chainable { 733 | /** 734 | * Lock the report 735 | * 736 | * @example cy.lockReport(TEST.REPORT.EXAMPLE); 737 | */ 738 | lockReport(report: string): Chainable; 739 | } 740 | } 741 | } 742 | Cypress.Commands.add('lockReport', (report) => { 743 | cy.jobDump(report).rightclick(); 744 | cy.get(AA4MF.lockReport); 745 | }); 746 | 747 | declare namespace Cypress { 748 | interface Chainable { 749 | /** 750 | * Unock the report 751 | * 752 | * @example cy.lockReport(TEST.REPORT.EXAMPLE); 753 | */ 754 | unlockReport(report: string): Chainable; 755 | } 756 | } 757 | Cypress.Commands.add('unlockReport', (report) => { 758 | cy.jobDump(report).rightclick(); 759 | cy.get(AA4MF.unlockReport); 760 | }); 761 | -------------------------------------------------------------------------------- /tests/src/theiaActions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | /* eslint-disable @typescript-eslint/no-namespace */ 16 | 17 | /// 18 | 19 | import { Theia, VSCODE } from './selectors'; 20 | import 'cypress-real-events/support'; 21 | 22 | const env = Cypress.env('ide'); 23 | const IDE = env === 'theia' ? Theia : VSCODE; 24 | const theiaMod = Theia.collapsed; 25 | const theiaModwoDot = theiaMod.replace(/^./, ''); 26 | 27 | declare global { 28 | /** 29 | * A workaround that has allowed me to add import and export 30 | * statements to my *.ts files is to explicitly declare 31 | * Cypress on the global namespace. 32 | */ 33 | namespace Cypress { 34 | interface Chainable { 35 | /** 36 | * Wait for application to be fully loaded. 37 | * 38 | * @example cy.waitForAppStart() 39 | */ 40 | waitForAppStart(): Chainable; 41 | } 42 | } 43 | } 44 | 45 | Cypress.Commands.add('waitForAppStart', () => { 46 | cy.get(IDE.mainContentPanel, { 47 | timeout: Cypress.env('appStarTimeout'), 48 | }); 49 | if (IDE === Theia) { 50 | cy.get(Theia.preLoad).should('not.exist', { 51 | timeout: Cypress.env('appStartTimeout'), 52 | }); 53 | cy.get(Theia.loadSpinner).should('not.exist', { 54 | timeout: Cypress.env('appStartTimeout'), 55 | }); 56 | } 57 | }); 58 | 59 | declare global { 60 | namespace Cypress { 61 | interface Chainable { 62 | /** 63 | * Refresh the page. 64 | * 65 | * @example cy.refreshPage() 66 | */ 67 | refreshPage(): Chainable; 68 | } 69 | } 70 | } 71 | Cypress.Commands.add('refreshPage', () => { 72 | cy.location('href', { log: false }).then((url) => { 73 | cy.visit(url, { 74 | onBeforeLoad: (win) => (win.fetch = null as any), 75 | }); 76 | }); 77 | }); 78 | 79 | declare global { 80 | namespace Cypress { 81 | interface Chainable { 82 | /** 83 | * Open File Explorer panel if it is closed. 84 | * 85 | * @example cy.openFileExplorer() 86 | */ 87 | openFileExplorer(): Chainable; 88 | } 89 | } 90 | } 91 | Cypress.Commands.add('openFileExplorer', () => { 92 | cy.get(IDE.leftRightPanel).then(($ide) => { 93 | // @ts-ignore 94 | if ($ide.find(IDE.elementCollapsed).length || $ide.find(IDE.explorerId).length) { 95 | cy.get(IDE.explorerIcon).click(); 96 | } 97 | if (IDE === Theia) { 98 | cy.hideSourceView(); 99 | } 100 | }); 101 | }); 102 | 103 | declare global { 104 | namespace Cypress { 105 | interface Chainable { 106 | /** 107 | * Find node (file or folder) in File Explorer tree. 108 | * 109 | * @example cy.findExplorerTreeNode('SOURCE.cbl') 110 | * @example cy.findExplorerTreeNode('.copybooks') 111 | */ 112 | findExplorerTreeNode(nodeName: string): Chainable; 113 | } 114 | } 115 | } 116 | Cypress.Commands.add('findExplorerTreeNode', (nodeName: string) => { 117 | cy.openFileExplorer(); 118 | cy.get(IDE.explorerView).contains(nodeName); 119 | }); 120 | 121 | declare global { 122 | namespace Cypress { 123 | interface Chainable { 124 | /** 125 | * Reveal folder content if it is collapsed in File Explorer tree. 126 | * 127 | * @example cy.openFolder('.copybooks') 128 | * @example cy.openFolder('.copybooks/zowe-profile') 129 | */ 130 | openFolder(path: string): Chainable; 131 | } 132 | } 133 | } 134 | Cypress.Commands.add('openFolder', (path: string) => { 135 | cy.wrap(path.split('/')).each((folderName: string) => { 136 | cy.findExplorerTreeNode(folderName) 137 | .as('folder') 138 | .then(($folder: { siblings: (arg0: string) => { (): any; new (): any; length: any } }) => { 139 | if (IDE === Theia) { 140 | if ($folder.siblings(Theia.collapsed).length) { 141 | cy.wrap($folder).click({ force: true }); 142 | cy.get('@folder').siblings().should('not.have.class', theiaModwoDot); 143 | } 144 | } else { 145 | cy.wrap($folder).click({ force: true }); 146 | } 147 | }); 148 | }); 149 | }); 150 | 151 | declare global { 152 | namespace Cypress { 153 | interface Chainable { 154 | /** 155 | * Close folder content. 156 | * 157 | * @example cy.closeFolder('.copybooks') 158 | * @example cy.closeFolder('.copybooks/zowe-profile') 159 | */ 160 | closeFolder(path: string): Chainable; 161 | } 162 | } 163 | } 164 | Cypress.Commands.add('closeFolder', (path: string) => { 165 | cy.wrap(path.split('/')).each((folderName: string) => { 166 | cy.findExplorerTreeNode(folderName) 167 | .as('folder') 168 | .then(($folder) => { 169 | cy.wrap($folder).click({ force: true }); 170 | if (IDE === Theia) { 171 | cy.get('@folder').siblings().should('have.class', theiaModwoDot); 172 | } 173 | }); 174 | }); 175 | }); 176 | 177 | declare global { 178 | namespace Cypress { 179 | interface Chainable { 180 | /** 181 | * Create new file in given path. 182 | * 183 | * @example cy.createNewFile('.copybooks/profile', 'COPYBOOK.cpy') 184 | */ 185 | createNewFile(path: string, fileName: string): Chainable; 186 | } 187 | } 188 | } 189 | Cypress.Commands.add('createNewFile', (path: string, fileName: string) => { 190 | cy.openFolder(path); 191 | //@ts-ignore 192 | cy.findExplorerTreeNode(path.split('/').pop()).type('{alt}{n}'); 193 | cy.get(IDE.dialogInput).type(`${fileName}{enter}`); 194 | cy.findExplorerTreeNode(fileName); 195 | }); 196 | 197 | declare global { 198 | namespace Cypress { 199 | interface Chainable { 200 | /** 201 | * Open file with a give name in File Explorer tree. Tree must be expanded first. 202 | * Editor tab disappeares on opening another file. 203 | * 204 | * @example cy.openFolder('.copybooks/profile').openFile('COPYBOOK.cpy') 205 | */ 206 | openFile(fileName: string): Chainable; 207 | } 208 | } 209 | } 210 | Cypress.Commands.add('openFile', (fileName: string) => { 211 | cy.wait(500).findExplorerTreeNode(fileName).dblclick({ force: true }); 212 | if (IDE === Theia) { 213 | cy.get(`[id^="shell-tab"][title*="${fileName}"]`); 214 | cy.get(Theia.loadSpinner).should('not.exist'); 215 | } else { 216 | cy.get(`[data-resource-name="${fileName}"]`); 217 | } 218 | }); 219 | 220 | declare global { 221 | namespace Cypress { 222 | interface Chainable { 223 | /** 224 | * Open file with a give name in File Explorer tree. Tree must be expanded first. 225 | * Editor tab remains on opening another file. 226 | * 227 | * @example cy.openFolder('.copybooks/profile').openFilePermanent('COPYBOOK.cpy') 228 | */ 229 | openFilePermanent(fileName: string): Chainable; 230 | } 231 | } 232 | } 233 | Cypress.Commands.add('openFilePermanent', (fileName: string) => { 234 | cy.findExplorerTreeNode(fileName).click({ force: true }).dblclick({ force: true }); 235 | cy.get(IDE.tabOpened + `[id*="${fileName}"]`); 236 | if (IDE === Theia) { 237 | cy.get(Theia.loadSpinner).should('not.exist'); 238 | } 239 | }); 240 | 241 | declare global { 242 | namespace Cypress { 243 | interface Chainable { 244 | /** 245 | * Delete file with a given name from File Explorer tree. Tree must be expaned first. 246 | * 247 | * @example cy.openFolder('.copybooks/profile').deleteFile('COPYBOOK.cpy') 248 | */ 249 | deleteFile(fileName: string): Chainable; 250 | } 251 | } 252 | } 253 | Cypress.Commands.add('deleteFile', (fileName: string) => { 254 | cy.findExplorerTreeNode(fileName).type('{del}'); 255 | if (IDE === Theia) { 256 | cy.get(IDE.dialogTitle) 257 | .contains('Delete File') 258 | .parent() 259 | .siblings(IDE.dialogContent) 260 | .contains(fileName) 261 | .parent() 262 | .siblings(IDE.dialogControl) 263 | .find('button' + IDE.theiaButtonOK) 264 | .contains('OK') 265 | .click({ force: true }); 266 | } else { 267 | cy.get(IDE.dialogContent).contains(fileName); 268 | cy.get(IDE.dialogControl).find(VSCODE.button).contains('Delete').click({ force: true }); 269 | } 270 | }); 271 | 272 | declare global { 273 | namespace Cypress { 274 | interface Chainable { 275 | /** 276 | * Get currently open editor tab. 277 | */ 278 | getCurrentTab(): Chainable; 279 | } 280 | } 281 | } 282 | Cypress.Commands.add('getCurrentTab', () => { 283 | if (IDE === VSCODE) { 284 | cy.get(IDE.currentTab).eq(0); 285 | } else { 286 | cy.get(IDE.currentTab); 287 | } 288 | }); 289 | 290 | declare global { 291 | namespace Cypress { 292 | interface Chainable { 293 | /** 294 | * Close currently open editor tab. 295 | */ 296 | closeCurrentTab(): Chainable; 297 | } 298 | } 299 | } 300 | Cypress.Commands.add('closeCurrentTab', () => { 301 | if (IDE == Theia) { 302 | cy.getCurrentTab().find(Theia.tabCloseButton).click({ force: true }); 303 | } else { 304 | cy.getCurrentTab().wait(500).rightclick(); 305 | cy.wait(500).get('[aria-label="Close All"]').click({ force: true }); 306 | cy.get('body').then(($body) => { 307 | if ($body.find(VSCODE.buttonDontSave).length > 0) { 308 | cy.get(VSCODE.buttonDontSave).click({ force: true }); 309 | } 310 | }); 311 | } 312 | }); 313 | 314 | declare global { 315 | namespace Cypress { 316 | interface Chainable { 317 | /** 318 | * Go to specified line inside open editor. 319 | * 320 | * @example cy.goToLine(42) 321 | */ 322 | goToLine(lineNumber: number): Chainable; 323 | } 324 | } 325 | } 326 | Cypress.Commands.add('goToLine', (lineNumber: number) => { 327 | if (IDE === Theia) { 328 | cy.get('#theia-main-content-panel .theia-editor') 329 | .not(Theia.modHidden) 330 | .not(Theia.bottomContentPanel) 331 | .type('{ctrl}g'); 332 | } else { 333 | cy.get(VSCODE.mainContentPanel).wait(500).type('{ctrl}g'); 334 | } 335 | 336 | cy.get(IDE.typeALineNumber).type(`${lineNumber}{enter}`, { 337 | delay: 100, 338 | }); 339 | cy.getCurrentLineNumber().should('eq', lineNumber); 340 | }); 341 | 342 | declare global { 343 | namespace Cypress { 344 | interface Chainable { 345 | /** 346 | * Find Language Mode 347 | * 348 | * @example cy.selectLangMode() 349 | */ 350 | selectLangMode(): Chainable; 351 | } 352 | } 353 | } 354 | Cypress.Commands.add('selectLangMode', () => { 355 | cy.get(IDE.languageMode); 356 | }); 357 | 358 | declare global { 359 | namespace Cypress { 360 | interface Chainable { 361 | /** 362 | * Change Language Mode 363 | * 364 | * @example cy.changeLangMode('COBOL Copybook') 365 | */ 366 | changeLangMode(mode: string): Chainable; 367 | } 368 | } 369 | } 370 | Cypress.Commands.add('changeLangMode', (mode: string) => { 371 | cy.selectLangMode().click().wait(500).type(`${mode}{enter}`).should('contain.text', mode); 372 | }); 373 | 374 | declare global { 375 | namespace Cypress { 376 | interface Chainable { 377 | /** 378 | * Get line content by its number. 379 | * 380 | * @example cy.getLineByNumber(42).contains('This is answer') 381 | */ 382 | getLineByNumber(lineNumber: number): Chainable; 383 | } 384 | } 385 | } 386 | Cypress.Commands.add('getLineByNumber', (lineNumber: number) => { 387 | cy.goToLine(lineNumber); 388 | cy.get(IDE.lineNumber) 389 | .contains(RegExp(`^${lineNumber}$`)) 390 | .parent() 391 | .should('have.css', 'top') 392 | .then((top) => { 393 | cy.get('.view-line').then(($lines) => { 394 | //@ts-ignore 395 | return $lines.filter((i, line) => { 396 | //@ts-ignore 397 | if (RegExp(`top:\\s*${top}`).test(Cypress.$(line).attr('style'))) { 398 | return line; 399 | } 400 | }); 401 | }); 402 | }); 403 | }); 404 | 405 | declare global { 406 | namespace Cypress { 407 | interface Chainable { 408 | /** 409 | * Get main editor element in Theia 410 | * 411 | * @example cy.getMainEditor() 412 | */ 413 | getMainEditor(): Chainable; 414 | } 415 | } 416 | } 417 | Cypress.Commands.add('getMainEditor', () => { 418 | if (IDE === Theia) { 419 | cy.get(Theia.mainContentPanel + ' ' + Theia.editor).not(Theia.modHidden); 420 | } else { 421 | cy.get(VSCODE.mainContentPanel); 422 | } 423 | }); 424 | 425 | declare global { 426 | namespace Cypress { 427 | interface Chainable { 428 | /** 429 | * Get preview editor element in Theia (e.g. in "Go to References") 430 | * 431 | * @example cy.getPreviewEditor() 432 | */ 433 | getPreviewEditor(): Chainable; 434 | } 435 | } 436 | } 437 | Cypress.Commands.add('getPreviewEditor', () => { 438 | cy.get(IDE.peekViewWidget); 439 | }); 440 | 441 | declare global { 442 | namespace Cypress { 443 | interface Chainable { 444 | /** 445 | * Find current line overlay div, containing additional line info, e.g. errors. 446 | * 447 | * @example cy.getMainEditor().findCurrentLineOverlay() 448 | */ 449 | findCurrentLineOverlay(editor: Chainable): Chainable; 450 | } 451 | } 452 | } 453 | Cypress.Commands.add('findCurrentLineOverlay', { prevSubject: true }, (editor) => { 454 | cy.wrap(editor).find(IDE.currentLine).parent(); 455 | }); 456 | 457 | declare global { 458 | namespace Cypress { 459 | interface Chainable { 460 | /** 461 | * Find current line overlay position by top attribute. 462 | * 463 | * @example cy.getMainEditor().findCurrentLineTop() 464 | */ 465 | findCurrentLineTop(editor: any): Chainable; 466 | } 467 | } 468 | } 469 | Cypress.Commands.add('findCurrentLineTop', { prevSubject: true }, (editor) => { 470 | //@ts-ignore 471 | cy.wrap(editor).findCurrentLineOverlay().should('have.css', 'top'); 472 | }); 473 | 474 | declare global { 475 | namespace Cypress { 476 | interface Chainable { 477 | /** 478 | * Get current line (i.e. where cursor stands) content. 479 | * 480 | * @example cy.getCurrentLine().contains('This is answer') 481 | */ 482 | getCurrentLine(): Chainable; 483 | } 484 | } 485 | } 486 | Cypress.Commands.add('getCurrentLine', () => { 487 | cy.getMainEditor() 488 | .as('editor') 489 | //@ts-ignore 490 | .findCurrentLineTop() 491 | .then((top: any) => { 492 | cy.get('@editor').find(`.view-line[style*="top:${top}"]`); 493 | }); 494 | }); 495 | 496 | declare global { 497 | namespace Cypress { 498 | interface Chainable { 499 | /** 500 | * Get current line (i.e. where cursor stands) number. 501 | * 502 | * @example cy.getCurrentLineNumber().should('eq', 42) 503 | */ 504 | getCurrentLineNumber(): Chainable; 505 | } 506 | } 507 | } 508 | Cypress.Commands.add('getCurrentLineNumber', () => { 509 | cy.getMainEditor() 510 | .as('editor') 511 | //@ts-ignore 512 | .findCurrentLineTop() 513 | .then((top: any) => { 514 | //cy.get('@editor').find('.line-numbers').parent(`[style*="top:${top}"]`).invoke('text').then(parseFloat); 515 | cy.get('@editor') 516 | .find(IDE.lineNumber) 517 | .then(($lineNumbers) => { 518 | //@ts-ignore 519 | const $number = $lineNumbers.filter((i, number) => { 520 | //@ts-ignore 521 | if (RegExp(`top:\\s*${top}`).test(Cypress.$(number.parentElement).attr('style'))) { 522 | return number; 523 | } 524 | }); 525 | return parseFloat($number[0].innerText); 526 | }); 527 | }); 528 | }); 529 | 530 | declare global { 531 | namespace Cypress { 532 | interface Chainable { 533 | /** 534 | * Get current line number in preview. 535 | * 536 | * @example cy.getPreviewCurrentLineNumber().should('eq', 42) 537 | */ 538 | getPreviewCurrentLineNumber(): Chainable; 539 | } 540 | } 541 | } 542 | Cypress.Commands.add('getPreviewCurrentLineNumber', () => { 543 | cy.getPreviewEditor() 544 | .as('previewEditor') 545 | //@ts-ignore 546 | .findCurrentLineTop() 547 | .then((top) => { 548 | cy.get('@previewEditor').find(IDE.lineNumber).parent(`[style*="top:${top}"]`).invoke('text').then(parseFloat); 549 | }); 550 | }); 551 | 552 | declare global { 553 | namespace Cypress { 554 | interface Chainable { 555 | /** 556 | * Get current line overlay. 557 | * 558 | * @example cy.getMainEditor().findCurrentLineOverlay() 559 | */ 560 | getCurrentLineOverlay(): Chainable; 561 | } 562 | } 563 | } 564 | Cypress.Commands.add('getCurrentLineOverlay', () => { 565 | //@ts-ignore 566 | cy.getMainEditor().findCurrentLineOverlay(); 567 | }); 568 | 569 | declare global { 570 | namespace Cypress { 571 | interface Chainable { 572 | /** 573 | * Get current line errors. by default error type is 'error'. 574 | * 575 | * @example cy.getCurrentLineErrors({ expectedLine: 41, errorType: "warning" }) 576 | */ 577 | getCurrentLineErrors(): Chainable; 578 | } 579 | } 580 | } 581 | Cypress.Commands.add( 582 | 'getCurrentLineErrors', 583 | ({ expectedLine, errorType = 'error' }: { expectedLine: number; errorType: string }) => { 584 | const errorTypes = { 585 | info: IDE.editorInfo, 586 | warning: IDE.editorWarn, 587 | error: IDE.editorError, 588 | }; 589 | // Wait until any errors parsed at all 590 | //@ts-ignore 591 | cy.getMainEditor().find(errorTypes[errorType]); 592 | // After that find errors in specific line 593 | cy.getCurrentLineOverlay() 594 | //@ts-ignore 595 | .find(errorTypes[errorType]) 596 | //@ts-ignore 597 | .then(($error: Element) => { 598 | //@ts-ignore 599 | cy.wrap($error).getElementLineNumber().should('eq', expectedLine); 600 | // Yield errors element instead of its line number 601 | cy.wrap($error); 602 | }); 603 | }, 604 | ); 605 | 606 | declare global { 607 | namespace Cypress { 608 | interface Chainable { 609 | /** 610 | * Get hover error message, e.g. on missing copybooks, semantic errors and so on. 611 | * 612 | * @example cy.getHoverErrorMessage() 613 | .contains("ABC: Copybook not foundCOBOL Language Support - E(MISSING_COPYBOOK)"); 614 | */ 615 | getHoverErrorMessage($error: Element, $text: string): Chainable; 616 | } 617 | } 618 | } 619 | Cypress.Commands.add('getHoverErrorMessage', { prevSubject: true }, ($error: Element, text: string) => { 620 | if (IDE === Theia) { 621 | //@ts-ignore 622 | cy.getCurrentLine().trigger('mousemove', $error[0].offsetLeft, $error[0].offsetTop); 623 | } else { 624 | //@ts-ignore 625 | cy.getCurrentLine().findText(text).realHover({ position: 'center' }); 626 | } 627 | cy.get(IDE.hoverOverContent); 628 | }); 629 | 630 | declare global { 631 | namespace Cypress { 632 | interface Chainable { 633 | /** 634 | * Get given editor element line number. 635 | * 636 | * @example cy.getSyntaxErrors().getElementLineNumber().should('eq', 42) 637 | */ 638 | getElementLineNumber(prevSubject: any, subject: any): Chainable; 639 | } 640 | } 641 | } 642 | Cypress.Commands.add('getElementLineNumber', { prevSubject: true }, (subject: Cypress.Chainable) => { 643 | cy.wrap(subject) 644 | .parent() 645 | .should('have.css', 'top') 646 | .then((top) => { 647 | cy.get(IDE.lineNumber).parent(`[style*="top:${top}"]`).invoke('text').then(parseFloat); 648 | }); 649 | }); 650 | 651 | declare global { 652 | namespace Cypress { 653 | interface Chainable { 654 | /** 655 | * Get element with specified text in given editor line. 656 | * Must be chained of editor line element. 657 | * 658 | * @example cy.getCurrentLine().findText("100-Print-User.") 659 | */ 660 | findText(prevSubject: any, subject: any, text: string): Chainable; 661 | } 662 | } 663 | } 664 | Cypress.Commands.add('findText', { prevSubject: true }, (subject: Cypress.Chainable, text: string) => { 665 | cy.wrap(subject).find('span').contains(text).click(); 666 | }); 667 | 668 | declare global { 669 | namespace Cypress { 670 | interface Chainable { 671 | /** 672 | * Go to definition of given syntax construction. 673 | * Must be chained of text element. 674 | * 675 | * @example cy.getCurrentLine().findText("100-Print-User.").goToDefinition() 676 | */ 677 | goToDefinition(prevSubject: any, $subject: any): Chainable; 678 | } 679 | } 680 | } 681 | Cypress.Commands.add('goToDefinition', { prevSubject: true }, ($subject: Cypress.Chainable) => { 682 | if (IDE === Theia) { 683 | cy.wrap($subject).wait(1000).rightclick().wait(2000); // wait for onClickListeneres to be set 684 | cy.get('.p-Widget.p-Menu').find(IDE.goToDefinition).click({ force: true }).wait(500); 685 | } else { 686 | cy.wrap($subject).wait(1000).rightclick(); 687 | cy.get('.shadow-root-host').shadow().find('.action-label').contains('Go to Definition').click(); 688 | } 689 | }); 690 | 691 | declare global { 692 | namespace Cypress { 693 | interface Chainable { 694 | /** 695 | * Go to references of given syntax construction. 696 | * Must be chained of text element. 697 | * 698 | * @example cy.getCurrentLine().findText("100-Print-User.").goToReferences() 699 | */ 700 | goToReferences(prevSubject: any, $subject: any): Chainable; 701 | } 702 | } 703 | } 704 | Cypress.Commands.add('goToReferences', { prevSubject: true }, ($subject: Cypress.Chainable) => { 705 | cy.wrap($subject).wait(1000).rightclick({ force: true }).wait(2000); // wait for onClickListeneres to be set 706 | if (IDE === Theia) { 707 | cy.get('.p-Widget.p-Menu').find(Theia.goToReference).click(); 708 | } else { 709 | cy.get('.shadow-root-host').shadow().find('.action-label').contains('Go to References').click(); 710 | } 711 | }); 712 | 713 | declare global { 714 | namespace Cypress { 715 | interface Chainable { 716 | /** 717 | * Go to definition of given syntax construction. 718 | * Must be chained of text element. 719 | * 720 | * @example cy.formatDocument() 721 | */ 722 | formatDocument(): Chainable; 723 | } 724 | } 725 | } 726 | Cypress.Commands.add('formatDocument', () => { 727 | if (IDE === Theia) { 728 | cy.get(Theia.mainContentPanel + ' ' + Theia.editor) 729 | .wait(1000) 730 | .rightclick() 731 | .wait(2000); // wait for onClickListeneres to be set 732 | cy.get('.p-Widget.p-Menu').find(IDE.formatDocument).click(); 733 | } else { 734 | cy.get(VSCODE.mainContentPanel).wait(1000).rightclick().wait(2000); // wait for onClickListeneres to be set 735 | cy.get('.shadow-root-host').shadow().find('.action-label').contains('Format Document').click(); 736 | } 737 | }); 738 | 739 | declare global { 740 | namespace Cypress { 741 | interface Chainable { 742 | /** 743 | * Hide Source View to have all files open in the Workspace 744 | * @example cy.hideSourceView() 745 | */ 746 | hideSourceView(): Chainable; 747 | } 748 | } 749 | } 750 | Cypress.Commands.add('hideSourceView', () => { 751 | cy.get(Theia.slidePanelTitile).contains('Explorer').rightclick({ force: true }); 752 | cy.get(Theia.menuContent).then(($menu) => { 753 | if ($menu.find('.p-mod-toggled:contains(Source View)').length) { 754 | cy.get(Theia.modToggled).contains('Source View').click(); 755 | } else { 756 | cy.get('body').type('{esc}', { delay: 100 }); 757 | } 758 | }); 759 | }); 760 | 761 | declare global { 762 | namespace Cypress { 763 | interface Chainable { 764 | /** 765 | * Opens Outline view. And do nothing if the view is already opened. 766 | * @example cy.openOutlineView() 767 | */ 768 | openOutlineView(): void; 769 | } 770 | } 771 | } 772 | Cypress.Commands.add('openOutlineView', () => { 773 | cy.get(IDE.outlineViewTab).then(($btn) => { 774 | if (!$btn.hasClass(IDE.modCurrent)) { 775 | cy.get(IDE.outlineViewTab).click(); 776 | } 777 | }); 778 | }); 779 | 780 | declare global { 781 | namespace Cypress { 782 | interface Chainable { 783 | /** 784 | * Expands the element in Outline view. 785 | * @example cy.expandOutlineElement('DATA DIVISION') 786 | */ 787 | expandOutlineElement(elementName: string): void; 788 | } 789 | } 790 | } 791 | Cypress.Commands.add('expandOutlineElement', (elementName: string) => { 792 | cy.getOutlineViewTreeContainer() 793 | .get(IDE.treeNodeSegment) 794 | .contains(elementName) 795 | .as('element') 796 | .then(($element) => { 797 | if (IDE === Theia) { 798 | if ($element.siblings(IDE.collapsed).length) { 799 | cy.wrap($element).click({ force: true }); 800 | cy.get('@element').siblings().should('not.have.class', IDE.collapsed); 801 | } 802 | } else { 803 | cy.wrap($element).click({ force: true }); 804 | } 805 | }); 806 | }); 807 | 808 | declare global { 809 | namespace Cypress { 810 | interface Chainable { 811 | /** 812 | * Returns the tree container from Outline view. 813 | * @example cy.getOutlineViewTreeContainer() 814 | */ 815 | getOutlineViewTreeContainer(): Chainable; 816 | } 817 | } 818 | } 819 | Cypress.Commands.add('getOutlineViewTreeContainer', (): any => cy.get(IDE.outlineView).get(IDE.treeContainer)); 820 | 821 | declare global { 822 | namespace Cypress { 823 | interface Chainable { 824 | /** 825 | * Read and write JSON file 826 | * Copy from test_files/project/settings/ specific settings json file 827 | * and paste to .theia/settings.json and .vscode/settings.json 828 | * @example cy.updateConfigs('basic') 829 | */ 830 | updateConfigs(expression: string): Chainable; 831 | } 832 | } 833 | } 834 | Cypress.Commands.add('updateConfigs', (expression: string) => { 835 | cy.readFile(`test_files/project/settings/${expression}.json`).then((content) => { 836 | cy.writeFile('test_files/project/.vscode/settings.json', content); 837 | if (IDE === Theia) { 838 | cy.writeFile('test_files/project/.theia/settings.json', content); 839 | } 840 | }); 841 | }); 842 | -------------------------------------------------------------------------------- /tests/src/zowe.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Broadcom. 3 | * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. 4 | 5 | * This program and the accompanying materials are made 6 | * available under the terms of the Eclipse Public License 2.0 7 | * which is available at https://www.eclipse.org/legal/epl-2.0/ 8 | 9 | * SPDX-License-Identifier: EPL-2.0 10 | 11 | * Contributors: 12 | * Broadcom, Inc. - initial API and implementation 13 | */ 14 | 15 | /* eslint-disable @typescript-eslint/no-namespace */ 16 | 17 | /// 18 | import { Theia, ZOWE } from './selectors'; 19 | 20 | declare global { 21 | /** 22 | * A workaround that has allowed me to add import and export 23 | * statements to my *.ts files is to explicitly declare 24 | * Cypress on the global namespace. 25 | */ 26 | namespace Cypress { 27 | interface Chainable { 28 | /** 29 | * Open ZOWE panel. 30 | * 31 | * @example cy.openZowePanel() 32 | */ 33 | openZowePanel(): Chainable; 34 | } 35 | } 36 | } 37 | Cypress.Commands.add('openZowePanel', () => { 38 | cy.get(Theia.leftRightPanel).then(($theia) => { 39 | if ($theia.find(Theia.elementCollapsed).length || $theia.find(ZOWE.zoweHidden).length) { 40 | cy.get(ZOWE.zoweView).click({ force: true }); 41 | } 42 | }); 43 | }); 44 | 45 | declare global { 46 | namespace Cypress { 47 | interface Chainable { 48 | /** 49 | * Add Zowe Profile. 50 | * 51 | * @example cy.addZoweProfile('TEST') 52 | */ 53 | addZoweProfile(profile: string): Chainable; 54 | } 55 | } 56 | } 57 | Cypress.Commands.add('addZoweProfile', (profile: string) => { 58 | cy.get(ZOWE.zowePluginView).trigger('mousedown').click(); 59 | cy.get(ZOWE.addSession).click(); 60 | cy.get(Theia.inputF1).as('quickOpen').type('{enter}').type(`${profile}{enter}`); 61 | cy.get('@quickOpen').type(Cypress.env('zowe'), { delay: 100 }).type('{enter}'); 62 | cy.get('@quickOpen').type(Cypress.env('username')).type('{enter}'); 63 | cy.get('@quickOpen') 64 | .type(Cypress.env('password'), { log: false, delay: 200 }) 65 | .then(($input) => { 66 | if ($input.val() !== Cypress.env('password')) { 67 | throw new Error('Different value of typed password'); 68 | } 69 | }) 70 | .type('{enter}') 71 | .type('{downarrow}') 72 | .type('{enter}') 73 | .type('{enter}') 74 | .type('{enter}') 75 | .type('{enter}'); 76 | }); 77 | 78 | declare global { 79 | namespace Cypress { 80 | interface Chainable { 81 | /** 82 | * Delete Zowe Profile. 83 | * 84 | * @example cy.deleteZoweProfile('TEST') 85 | */ 86 | deleteZoweProfile(profile: string): Chainable; 87 | } 88 | } 89 | } 90 | Cypress.Commands.add('deleteZoweProfile', (profile: string) => { 91 | cy.openZowePanel(); 92 | cy.get(ZOWE.zoweTreeContainer).contains(profile).rightclick(); 93 | cy.get(ZOWE.deleteProfile).click(); 94 | cy.get(Theia.inputF1).type('{enter}'); 95 | cy.get(Theia.notificationMessage).contains(`Profile ${profile} was deleted.`); 96 | }); 97 | 98 | declare global { 99 | namespace Cypress { 100 | interface Chainable { 101 | /** 102 | * Search Data Set. 103 | * 104 | * @example cy.searchDataSet('TEST','as12345.TEST') 105 | */ 106 | searchDataSet(profile: string, dataset: string): Chainable; 107 | } 108 | } 109 | } 110 | Cypress.Commands.add('searchDataSet', (profile: string, dataset: string) => { 111 | cy.get(ZOWE.zoweTreeContainer).contains(profile).trigger('mousedown').click(); 112 | cy.get(`.theia-TreeNodeContent [data-node-id*="/1:${profile}"]`).get('[title="Search Data Sets"]').click(); 113 | 114 | cy.get(Theia.inputF1).type(`${dataset}{enter}`, { delay: 100 }).type('{enter}'); 115 | }); 116 | 117 | declare global { 118 | namespace Cypress { 119 | interface Chainable { 120 | /** 121 | * Open Data Set under a Zowe profile 122 | * 123 | * @example cy.openDataSet('as12345.TEST') 124 | */ 125 | openDataSet(dataset: string): Chainable; 126 | } 127 | } 128 | } 129 | Cypress.Commands.add('openDataSet', (dataset: string) => { 130 | cy.get(`[data-node-id*="/0:${dataset}"]`).click().wait(3000); 131 | }); 132 | 133 | declare global { 134 | namespace Cypress { 135 | interface Chainable { 136 | /** 137 | * Open JCL 138 | * 139 | * @example cy.openJCL('JCLEXAMPLE','TEST', 'as12345.TEST') 140 | */ 141 | openJCL(jcl: string, profile: string, dataset: string): Chainable; 142 | } 143 | } 144 | } 145 | Cypress.Commands.add('openJCL', (jcl: string, profile: string, dataset: string) => { 146 | cy.get(`[id*="/1:${profile} /0:${dataset}/2:${jcl}"]`).click().click(); 147 | }); 148 | 149 | declare global { 150 | namespace Cypress { 151 | interface Chainable { 152 | /** 153 | * Open Jobs Sections 154 | * 155 | * @example cy.openJobs('TEST', '(TSU01772) - ABEND S222', 'JES2:JESJCL(3)'); 156 | */ 157 | openJobs(profile: string, folder: string, jobName: string): Chainable; 158 | } 159 | } 160 | } 161 | Cypress.Commands.add('openJobs', (profile: string, folder: string, jobName: string) => { 162 | //@ts-ignore 163 | cy.openZowePanel(); 164 | cy.get(ZOWE.zoweJobs).click().contains(profile).click(); 165 | cy.get(`[id*="/1:${profile}/0:${folder}"]`).click(); 166 | cy.get(`[id*="/1:${profile}/0:${folder}/1:${jobName}"]`).click(); 167 | }); 168 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "allowJs": true, 5 | "checkJs": true, 6 | "module": "CommonJS", 7 | "declaration": true, 8 | "declarationMap": true, 9 | "sourceMap": true, 10 | "outDir": "dist", 11 | "target": "ES6", 12 | "lib": ["ES6", "DOM"], 13 | "types": ["cypress", "node"] 14 | }, 15 | "include": ["src/**/*.ts", "./node_modules/cypress"], 16 | "exclude": ["dist", "node_modules"] 17 | } 18 | --------------------------------------------------------------------------------