diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..18d3ed3cc2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# https://EditorConfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[{*.java,pom.xml,*.py}] +indent_size = 4 diff --git a/.github/config.json b/.github/config.json index 4d348b0e78..912b66e812 100644 --- a/.github/config.json +++ b/.github/config.json @@ -1 +1,2267 @@ -{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widget design system":{"conditions":[{"label":"App Theming","type":"hasLabel","value":true},{"label":"Widget Styling","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"Billing & Usage Pod":{"conditions":[{"label":"BE Instance","type":"hasLabel","value":true},{"label":"CE Instance","type":"hasLabel","value":true},{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing Integrations","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"In-app ramps","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"1-click upgrade","type":"hasLabel","value":true},{"label":"Appsmith Business Cloud","type":"hasLabel","value":true}],"requires":1},"Mobile Pod":{"conditions":[],"requires":1},"Git Pod":{"conditions":[{"label":"Git Version Control","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"Integrations Pod":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true}],"requires":1},"Data Platform Pod":{"conditions":[{"label":"Datasource Environments","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"Page load executions","type":"hasLabel","value":true},{"label":"DSL Update","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true},{"label":"Deploy App","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"DocumentDB","type":"hasLabel","value":true},{"label":"Multiple Environments","type":"hasLabel","value":true},{"label":"Platformization","type":"hasLabel","value":true}],"requires":1},"Design System Pod":{"conditions":[{"label":"Design System Pod","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true}],"requires":1},"Team Managers Pod":{"conditions":[{"label":"Settings","type":"hasLabel","value":true},{"label":"Home Page","type":"hasLabel","value":true},{"label":"Invite users","type":"hasLabel","value":true},{"label":"Realtime Commenting","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"Multi User Realtime","type":"hasLabel","value":true},{"label":"RBAC","type":"hasLabel","value":true},{"label":"ABAC","type":"hasLabel","value":true},{"label":"Audit Logs","type":"hasLabel","value":true},{"label":"Multitenancy","type":"hasLabel","value":true},{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true}],"requires":1},"New Developers Pod":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Onboarding","type":"hasLabel","value":true},{"label":"Telemetry","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Generate Page","type":"hasLabel","value":true},{"label":"IDE","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"Example Apps","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"Welcome Screen","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"Clean URLs","type":"hasLabel","value":true},{"label":"Embedding Apps","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true},{"label":"In App Comms","type":"hasLabel","value":true},{"label":"In App Comms","type":"hasLabel","value":true}],"requires":1},"BE Coders Pod":{"conditions":[{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"SAAS Manager App","type":"hasLabel","value":true},{"label":"Data Platform Pod","type":"hasLabel","value":true},{"label":"Integrations Pod","type":"hasLabel","value":true}],"requires":1},"FE Coders Pod":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Debugger","type":"hasLabel","value":true},{"label":"JS Snippets","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Promises","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Code Refactoring","type":"hasLabel","value":true},{"label":"storeValue","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"Code Editor","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"JS Function execution","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Error Handling","type":"hasLabel","value":true}],"requires":1},"App Viewers Pod":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"reallabel","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Branding","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"Widget design system","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true}],"requires":1},"UI Builders Pod":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Pages","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Canvas Zooms","type":"hasLabel","value":true},{"label":"Frontend Libraries Upgrade","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Responsive Canvas","type":"hasLabel","value":true},{"label":"Responsive Widget","type":"hasLabel","value":true},{"label":"Responsive Viewport","type":"hasLabel","value":true},{"label":"Conversion Algorithm","type":"hasLabel","value":true},{"label":"Spacing","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"widget vertical alignment","type":"hasLabel","value":true}],"requires":1},"User Education Pod":{"conditions":[{"label":"Content","type":"hasLabel","value":true},{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Templates pod":{"conditions":[{"label":"Templates","type":"hasLabel","value":true},{"label":"Community template","type":"hasLabel","value":true}],"requires":1},"Error Handling":{"conditions":[],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"88054d","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"e2ca68","name":"QA","description":""},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"9c0c8e","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Settings":{"color":"f7ff60","name":"Settings","description":"organization, team & user settings"},"Fork App":{"color":"5369db","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"Onboarding":{"color":"d5794b","name":"Onboarding","description":"Issues related to onboarding new developers"},"Pages":{"color":"d7fd80","name":"Pages","description":"Issues related to configuring pages"},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Widget Styling":{"color":"905420","name":"Widget Styling","description":"all about widget styling"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"App Viewers Pod":{"color":"cd8ef9","name":"App Viewers Pod","description":"This label assigns issues to the app viewers pod"},"Checkbox Widget":{"color":"88054d","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"d73a4a","name":"Bug","description":"Something isn't working"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"f14274","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Team Managers Pod":{"color":"bddb81","name":"Team Managers Pod","description":"Issues that team managers care about for the security and efficiency of their teams"},"Import-Export-App":{"color":"15076d","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"10b5ce","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"771e69","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Critical":{"color":"9b1b28","name":"Critical","description":"This issue needs immediate attention. Drop everything else"},"IDE":{"color":"61b2ee","name":"IDE","description":"Issues related to the IDE"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"f28253","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Git Version Control":{"color":"858172","name":"Git Version Control","description":"Issues related to version control"},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"a2e2f9","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Debugger":{"color":"e79062","name":"Debugger","description":"Issues related to the debugger"},"Quick effort":{"color":"95ED65","name":"Quick effort","description":"Something that'll take a few hours to build"},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"5052f6","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"UI Builders Pod":{"color":"517fba","name":"UI Builders Pod","description":"Issues that UI Builders face using appsmith"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"In App Comms":{"name":"In App Comms","description":"Issues around communication with appsmith instances","color":"463cca"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"BE Coders Pod":{"color":"5d9848","name":"BE Coders Pod","description":"Issues related to users writing code to fetch and update data"},"FE Coders Pod":{"color":"a7effc","name":"FE Coders Pod","description":"Issues related to users writing javascript in appsmith"},"New Developers Pod":{"color":"6310da","name":"New Developers Pod","description":"Issues that new developers face while exploring the IDE"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"6310da"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"12b715"},"Responsive Viewport":{"color":"d12d2e","name":"Responsive Viewport","description":"Issues seen on different viewports like mobile"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"Invite users":{"color":"1799b0","name":"Invite users","description":"Invite users flow and any associated actions"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"User Education Pod":{"name":"User Education Pod","description":"Issues related to user education","color":"1799b0"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Embedding Apps":{"name":"Embedding Apps","description":"Issues related to embedding","color":"26ef4f"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"ef9c9d"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"50559d"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"3897be"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"App Theming":{"name":"App Theming","description":"Items that are related to the App level theming controls epic","color":"905420"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":"bf019b"},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Templates":{"name":"Templates","description":"Issues related to templates","color":"b7e568"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"RBAC":{"name":"RBAC","description":"Issues, requests and enhancements around RBAC.","color":"9211c3"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"Tests":{"name":"Tests","description":"test item","color":"1c6990"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Design System Pod":{"name":"Design System Pod","description":"Appsmith design system related issues","color":"706f03"},"ABAC":{"color":"e009a5","name":"ABAC","description":"User permissions and access controls"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"60885f"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"bc0cba"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"e4d966"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"418fa4"},"Branding":{"name":"Branding","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"7aaaf1"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"Audit Logs":{"name":"Audit Logs","description":"Audit trails to ensure data security","color":"f3fd62"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Data Platform Pod":{"name":"Data Platform Pod","description":"Issues related to the underlying data platform","color":"3f8c3a"},"Integrations Pod":{"name":"Integrations Pod","description":"Issues related to a specific integration","color":"5dbbb1"},"Datasource Environments":{"name":"Datasource Environments","description":"Issues related to datasource environments","color":"bb7a14"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"418fa4","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"6a5b42"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"c7da7a"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"e4d966"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"e4d966"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"e4d966"},"Page load executions":{"name":"Page load executions","description":"Issues related to page load execution","color":"5696b2"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Git Pod":{"name":"Git Pod","description":"Anything related to git sync","color":"2e5ba4"},"Mobile Pod":{"name":"Mobile Pod","description":"All issues related to mobile responsiveness","color":"6c97fd"},"Responsive Widget":{"name":"Responsive Widget","description":"All issues related to widget responsiveness","color":"d12d2e"},"Responsive Canvas":{"name":"Responsive Canvas","description":"All issues related to canvas responsiveness","color":"45a0a8"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Spacing":{"name":"Spacing","description":"All issue related to spacing between widgets in auto layout","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Error Handling":{"name":"Error Handling","description":"Issues related to error handling","color":"4e1872"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"434a3a"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"c476eb"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"Billing & Usage Pod":{"name":"Billing & Usage Pod","description":"Issues pertaining to licensing, billing, usage across self serve and enterprise customers","color":"256808"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"8154df"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Widget design system":{"name":"Widget design system","description":"","color":"11cc90"},"Deploy App":{"name":"Deploy App","description":"Issues related to app deployment","color":"6f6152"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"BE Instance":{"name":"BE Instance","description":"For all issues relating to usage, licensing or billing on the BE instance","color":"d2bc40"},"CE Instance":{"name":"CE Instance","description":"For all issues relating to usage, licensing or billing on the CE instance","color":"d2bc40"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"Billing Integrations":{"name":"Billing Integrations","description":"For all issues relating to 3P integrations Appsmith is using for billing & usage","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Appsmith Business Cloud":{"name":"Appsmith Business Cloud","description":"Issues related to our business cloud offering","color":"89bb6c"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"In-app ramps":{"name":"In-app ramps","description":"For all tasks/issues relating to adding in-app ramps in the community edition of the product","color":"8abae0"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"1-click upgrade":{"name":"1-click upgrade","description":"For all issues/tasks related to 1-click upgrade & downgrade project","color":"129082"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging flagsmith","color":"728126"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"61a852"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Templates pod":{"name":"Templates pod","description":"Issues related to Templates","color":"b7e568"},"Community template":{"name":"Community template","description":"Label for development of community templates and its integration to platform","color":"8a0510"},"DocumentDB":{"name":"DocumentDB","description":"Issues related to support DocumentDB in Appsmith Data layer","color":"2c8b56"},"Multiple Environments":{"name":"Multiple Environments","description":"Issues or tasks related to multiple environments","color":"4e972b"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"}},"success":true} +{ + "runners": [ + { + "versioning": { "source": "milestones", "type": "SemVer" }, + "prereleaseName": "alpha", + "issue": { + "labels": { + "Widget design system": { + "conditions": [ + { "label": "App Theming", "type": "hasLabel", "value": true }, + { "label": "Widget Styling", "type": "hasLabel", "value": true }, + { + "label": "Checkbox Group widget", + "type": "hasLabel", + "value": true + }, + { "label": "Checkbox Widget", "type": "hasLabel", "value": true }, + { + "label": "Checkbox Component", + "type": "hasLabel", + "value": true + }, + { "label": "WDS team", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "Performance Pod": { + "conditions": [ + { "label": "Performance", "type": "hasLabel", "value": true }, + { + "label": "Performance infra", + "type": "hasLabel", + "value": true + } + ], + "requires": 1 + }, + "Billing & Usage Pod": { + "conditions": [ + { "label": "CE Instance", "type": "hasLabel", "value": true }, + { "label": "Customer Portal", "type": "hasLabel", "value": true }, + { "label": "Cloud Services", "type": "hasLabel", "value": true }, + { + "label": "Billing Integrations", + "type": "hasLabel", + "value": true + }, + { "label": "Billing", "type": "hasLabel", "value": true }, + { "label": "Self Serve", "type": "hasLabel", "value": true }, + { + "label": "Enterprise Billing", + "type": "hasLabel", + "value": true + }, + { "label": "In-app ramps", "type": "hasLabel", "value": true }, + { + "label": "Analytics Improvements", + "type": "hasLabel", + "value": true + }, + { "label": "Self Serve 1.0", "type": "hasLabel", "value": true }, + { "label": "License", "type": "hasLabel", "value": true }, + { "label": "1-click upgrade", "type": "hasLabel", "value": true }, + { + "label": "Appsmith Business Cloud", + "type": "hasLabel", + "value": true + }, + { "label": "BE instance", "type": "hasLabel", "value": true }, + { "label": "Feature Flagging", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "Mobile Pod": { "conditions": [], "requires": 1 }, + "Git Pod": { + "conditions": [ + { + "label": "Git Version Control", + "type": "hasLabel", + "value": true + }, + { + "label": "Import-Export-App", + "type": "hasLabel", + "value": true + } + ], + "requires": 1 + }, + "Integrations Pod": { + "conditions": [ + { "label": "New Datasource", "type": "hasLabel", "value": true }, + { "label": "Firestore", "type": "hasLabel", "value": true }, + { "label": "Google Sheets", "type": "hasLabel", "value": true }, + { "label": "Mongo", "type": "hasLabel", "value": true }, + { "label": "Redshift", "type": "hasLabel", "value": true }, + { "label": "snowflake", "type": "hasLabel", "value": true }, + { "label": "S3", "type": "hasLabel", "value": true }, + { "label": "Redis", "type": "hasLabel", "value": true }, + { "label": "Postgres", "type": "hasLabel", "value": true }, + { "label": "GraphQL Plugin", "type": "hasLabel", "value": true }, + { "label": "ArangoDB", "type": "hasLabel", "value": true }, + { "label": "MsSQL", "type": "hasLabel", "value": true }, + { "label": "REST API plugin", "type": "hasLabel", "value": true }, + { "label": "Elastic Search", "type": "hasLabel", "value": true }, + { "label": "OAuth", "type": "hasLabel", "value": true }, + { "label": "Airtable", "type": "hasLabel", "value": true }, + { "label": "CURL", "type": "hasLabel", "value": true }, + { "label": "DynamoDB", "type": "hasLabel", "value": true }, + { "label": "Zendesk", "type": "hasLabel", "value": true }, + { "label": "Hubspot", "type": "hasLabel", "value": true }, + { "label": "Query Forms", "type": "hasLabel", "value": true }, + { "label": "Twilio", "type": "hasLabel", "value": true }, + { "label": "MySQL", "type": "hasLabel", "value": true }, + { "label": "Connection pool", "type": "hasLabel", "value": true }, + { "label": "MariaDB", "type": "hasLabel", "value": true }, + { + "label": "Integrations Pod General", + "type": "hasLabel", + "value": true + }, + { "label": "SMTP plugin", "type": "hasLabel", "value": true }, + { "label": "Oracle SQL DB", "type": "hasLabel", "value": true }, + { "label": "Query filter", "type": "hasLabel", "value": true }, + { + "label": "Activation - datasources", + "type": "hasLabel", + "value": true + } + ], + "requires": 1 + }, + "Data Platform Pod": { + "conditions": [ + { + "label": "Datasource Environments", + "type": "hasLabel", + "value": true + }, + { "label": "Datatype issue", "type": "hasLabel", "value": true }, + { "label": "Entity Refactor", "type": "hasLabel", "value": true }, + { + "label": "Core Query Execution", + "type": "hasLabel", + "value": true + }, + { + "label": "Query Management", + "type": "hasLabel", + "value": true + }, + { "label": "Query Settings", "type": "hasLabel", "value": true }, + { + "label": "SmartSubstitution", + "type": "hasLabel", + "value": true + }, + { + "label": "Query Generation", + "type": "hasLabel", + "value": true + }, + { + "label": "Query performance", + "type": "hasLabel", + "value": true + }, + { + "label": "Suggested Widgets", + "type": "hasLabel", + "value": true + }, + { + "label": "Page load executions", + "type": "hasLabel", + "value": true + }, + { "label": "DSL Update", "type": "hasLabel", "value": true }, + { "label": "AST-backend", "type": "hasLabel", "value": true }, + { "label": "Deploy App", "type": "hasLabel", "value": true }, + { + "label": "File upload issues", + "type": "hasLabel", + "value": true + }, + { "label": "Datasources", "type": "hasLabel", "value": true }, + { "label": "DocumentDB", "type": "hasLabel", "value": true }, + { + "label": "Multiple Environments", + "type": "hasLabel", + "value": true + }, + { "label": "Platformization", "type": "hasLabel", "value": true }, + { + "label": "Custom environments", + "type": "hasLabel", + "value": true + }, + { "label": "Schema", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "Design System Pod": { + "conditions": [ + { + "label": "Design System Pod", + "type": "hasLabel", + "value": true + }, + { + "label": "ADS Component Issue", + "type": "hasLabel", + "value": true + }, + { + "label": "Keyboard accessibility ", + "type": "hasLabel", + "value": true + }, + { "label": "Toggle button", "type": "hasLabel", "value": true }, + { + "label": "ADS Category Token", + "type": "hasLabel", + "value": true + }, + { + "label": "ADS Component Documentation", + "type": "hasLabel", + "value": true + }, + { "label": "ADS Migration", "type": "hasLabel", "value": true }, + { + "label": "ADS Deduplication ", + "type": "hasLabel", + "value": true + }, + { "label": "ADS Revamp", "type": "hasLabel", "value": true }, + { + "label": "ADS Deduplication", + "type": "hasLabel", + "value": true + }, + { "label": "ADS Unit Test", "type": "hasLabel", "value": true }, + { "label": "ADS Components", "type": "hasLabel", "value": true }, + { "label": "ADS Grayscale", "type": "hasLabel", "value": true }, + { "label": "Design System", "type": "hasLabel", "value": true }, + { "label": "ADS Typography", "type": "hasLabel", "value": true }, + { + "label": "ADS Visual Styles", + "type": "hasLabel", + "value": true + }, + { + "label": "ADS Component Design", + "type": "hasLabel", + "value": true + }, + { "label": "Modal Component", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "DevOps Pod": { + "conditions": [ + { "label": "Docker", "type": "hasLabel", "value": true }, + { "label": "Super Admin", "type": "hasLabel", "value": true }, + { "label": "Deployment", "type": "hasLabel", "value": true }, + { "label": "K8s", "type": "hasLabel", "value": true }, + { "label": "Email Config", "type": "hasLabel", "value": true }, + { + "label": "Backup & Restore", + "type": "hasLabel", + "value": true + }, + { "label": "AWS AMI", "type": "hasLabel", "value": true }, + { "label": "Observability", "type": "hasLabel", "value": true }, + { "label": "Heroku", "type": "hasLabel", "value": true }, + { + "label": "New Deployment Mode", + "type": "hasLabel", + "value": true + } + ], + "requires": 1 + }, + "Team Managers Pod": { + "conditions": [ + { "label": "Settings", "type": "hasLabel", "value": true }, + { "label": "Home Page", "type": "hasLabel", "value": true }, + { "label": "Invite users", "type": "hasLabel", "value": true }, + { + "label": "Realtime Commenting", + "type": "hasLabel", + "value": true + }, + { "label": "SSO", "type": "hasLabel", "value": true }, + { + "label": "Multi User Realtime", + "type": "hasLabel", + "value": true + }, + { "label": "RBAC", "type": "hasLabel", "value": true }, + { "label": "ABAC", "type": "hasLabel", "value": true }, + { "label": "Audit Logs", "type": "hasLabel", "value": true }, + { "label": "Multitenancy", "type": "hasLabel", "value": true }, + { "label": "Airgap", "type": "hasLabel", "value": true }, + { + "label": "Enterprise Edition", + "type": "hasLabel", + "value": true + }, + { "label": "SCIM", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "New Developers Pod": { + "conditions": [ + { "label": "Fork App", "type": "hasLabel", "value": true }, + { "label": "Omnibar", "type": "hasLabel", "value": true }, + { "label": "Onboarding", "type": "hasLabel", "value": true }, + { "label": "Telemetry", "type": "hasLabel", "value": true }, + { "label": "Entity Explorer", "type": "hasLabel", "value": true }, + { "label": "Generate Page", "type": "hasLabel", "value": true }, + { "label": "IDE", "type": "hasLabel", "value": true }, + { "label": "Sniping Mode", "type": "hasLabel", "value": true }, + { "label": "Example Apps", "type": "hasLabel", "value": true }, + { "label": "i18n", "type": "hasLabel", "value": true }, + { "label": "Welcome Screen", "type": "hasLabel", "value": true }, + { "label": "IDE Navigation", "type": "hasLabel", "value": true }, + { "label": "Login / Signup", "type": "hasLabel", "value": true }, + { "label": "Clean URLs", "type": "hasLabel", "value": true }, + { "label": "Embedding Apps", "type": "hasLabel", "value": true }, + { "label": "In App Comms", "type": "hasLabel", "value": true }, + { "label": "In App Comms", "type": "hasLabel", "value": true }, + { "label": "App setting", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "BE Coders Pod": { + "conditions": [ + { "label": "SAAS Plugins", "type": "hasLabel", "value": true }, + { + "label": "SAAS Manager App", + "type": "hasLabel", + "value": true + }, + { + "label": "Data Platform Pod", + "type": "hasLabel", + "value": true + }, + { "label": "Integrations Pod", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "FE Coders Pod": { + "conditions": [ + { + "label": "JS Linting & Errors", + "type": "hasLabel", + "value": true + }, + { "label": "Debugger", "type": "hasLabel", "value": true }, + { "label": "JS Snippets", "type": "hasLabel", "value": true }, + { "label": "Autocomplete", "type": "hasLabel", "value": true }, + { "label": "Evaluated Value", "type": "hasLabel", "value": true }, + { "label": "Slash Command", "type": "hasLabel", "value": true }, + { "label": "New JS Function", "type": "hasLabel", "value": true }, + { "label": "JS Promises", "type": "hasLabel", "value": true }, + { "label": "JS Usability", "type": "hasLabel", "value": true }, + { + "label": "Code Refactoring", + "type": "hasLabel", + "value": true + }, + { "label": "storeValue", "type": "hasLabel", "value": true }, + { "label": "OnPageLoad", "type": "hasLabel", "value": true }, + { + "label": "Framework Functions", + "type": "hasLabel", + "value": true + }, + { "label": "Code Editor", "type": "hasLabel", "value": true }, + { "label": "JS Objects", "type": "hasLabel", "value": true }, + { "label": "JS Evaluation", "type": "hasLabel", "value": true }, + { "label": "AST-frontend", "type": "hasLabel", "value": true }, + { + "label": "Custom JS Libraries", + "type": "hasLabel", + "value": true + }, + { "label": "Action Selector", "type": "hasLabel", "value": true }, + { + "label": "JS Function execution", + "type": "hasLabel", + "value": true + }, + { + "label": "Widget setter method", + "type": "hasLabel", + "value": true + }, + { "label": "Error Handling", "type": "hasLabel", "value": true }, + { "label": "AI", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "App Viewers Pod": { + "conditions": [ + { "label": "Button Widget", "type": "hasLabel", "value": true }, + { "label": "Chart Widget", "type": "hasLabel", "value": true }, + { + "label": "Container Widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Date Picker Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Select Widget", "type": "hasLabel", "value": true }, + { + "label": "File Picker Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Form Widget", "type": "hasLabel", "value": true }, + { "label": "Image Widget", "type": "hasLabel", "value": true }, + { "label": "Input Widget", "type": "hasLabel", "value": true }, + { "label": "List Widget", "type": "hasLabel", "value": true }, + { + "label": "MultiSelect Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Map Widget", "type": "hasLabel", "value": true }, + { "label": "Modal Widget", "type": "hasLabel", "value": true }, + { "label": "Radio Widget", "type": "hasLabel", "value": true }, + { + "label": "Rich Text Editor Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Tab Widget", "type": "hasLabel", "value": true }, + { "label": "Table Widget", "type": "hasLabel", "value": true }, + { "label": "Text Widget", "type": "hasLabel", "value": true }, + { "label": "Video Widget", "type": "hasLabel", "value": true }, + { "label": "iFrame", "type": "hasLabel", "value": true }, + { "label": "Menu Button", "type": "hasLabel", "value": true }, + { "label": "Rating", "type": "hasLabel", "value": true }, + { + "label": "Widget Validation", + "type": "hasLabel", + "value": true + }, + { "label": "reallabel", "type": "hasLabel", "value": true }, + { "label": "New Widget", "type": "hasLabel", "value": true }, + { "label": "Switch widget", "type": "hasLabel", "value": true }, + { "label": "Audio Widget", "type": "hasLabel", "value": true }, + { + "label": "Icon Button Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Stat Box Widget", "type": "hasLabel", "value": true }, + { + "label": "Voice Recorder Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Calendar Widget", "type": "hasLabel", "value": true }, + { + "label": "Menu Button Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Divider Widget", "type": "hasLabel", "value": true }, + { "label": "Rating Widget", "type": "hasLabel", "value": true }, + { "label": "App Navigation", "type": "hasLabel", "value": true }, + { "label": "View Mode", "type": "hasLabel", "value": true }, + { "label": "Widget Property", "type": "hasLabel", "value": true }, + { + "label": "Document Viewer Widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Radio Group Widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Currency Input Widget", + "type": "hasLabel", + "value": true + }, + { "label": "TreeSelect", "type": "hasLabel", "value": true }, + { + "label": "MultiTree Select Widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Phone Input Widget", + "type": "hasLabel", + "value": true + }, + { "label": "JSON Form", "type": "hasLabel", "value": true }, + { "label": "All Widgets", "type": "hasLabel", "value": true }, + { + "label": "Button Group widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Progress bar widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Audio Recorder Widget", + "type": "hasLabel", + "value": true + }, + { "label": "Camera Widget", "type": "hasLabel", "value": true }, + { "label": "Table Widget V2", "type": "hasLabel", "value": true }, + { "label": "Branding", "type": "hasLabel", "value": true }, + { + "label": "Map Chart Widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Code Scanner Widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Widget keyboard accessibility", + "type": "hasLabel", + "value": true + }, + { "label": "List Widget V2", "type": "hasLabel", "value": true }, + { "label": "Slider Widget", "type": "hasLabel", "value": true }, + { + "label": "Widget design system", + "type": "hasLabel", + "value": true + }, + { + "label": "One-click Binding", + "type": "hasLabel", + "value": true + }, + { + "label": "Old widget version", + "type": "hasLabel", + "value": true + }, + { + "label": "Widget Discoverability", + "type": "hasLabel", + "value": true + }, + { "label": "Custom widgets", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "UI Builders Pod": { + "conditions": [ + { "label": "Property Pane", "type": "hasLabel", "value": true }, + { "label": "Pages", "type": "hasLabel", "value": true }, + { "label": "Copy Paste", "type": "hasLabel", "value": true }, + { "label": "Drag & Drop", "type": "hasLabel", "value": true }, + { "label": "Undo/Redo", "type": "hasLabel", "value": true }, + { "label": "Widgets Pane", "type": "hasLabel", "value": true }, + { "label": "UI Performance", "type": "hasLabel", "value": true }, + { "label": "Widget Grouping", "type": "hasLabel", "value": true }, + { "label": "Reflow & Resize", "type": "hasLabel", "value": true }, + { "label": "Canvas / Grid", "type": "hasLabel", "value": true }, + { "label": "Canvas Zooms", "type": "hasLabel", "value": true }, + { + "label": "Frontend Libraries Upgrade", + "type": "hasLabel", + "value": true + }, + { "label": "Auto Height", "type": "hasLabel", "value": true }, + { + "label": "Responsive Canvas", + "type": "hasLabel", + "value": true + }, + { + "label": "Responsive Widget", + "type": "hasLabel", + "value": true + }, + { + "label": "Responsive Viewport", + "type": "hasLabel", + "value": true + }, + { + "label": "Conversion Algorithm", + "type": "hasLabel", + "value": true + }, + { "label": "Spacing", "type": "hasLabel", "value": true }, + { + "label": "Browser specific", + "type": "hasLabel", + "value": true + }, + { + "label": "widget vertical alignment", + "type": "hasLabel", + "value": true + }, + { "label": "Auto Layout", "type": "hasLabel", "value": true }, + { "label": "Fixed layout", "type": "hasLabel", "value": true }, + { "label": "Anvil layout", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "User Education Pod": { + "conditions": [ + { "label": "Content", "type": "hasLabel", "value": true }, + { "label": "Documentation", "type": "hasLabel", "value": true } + ], + "requires": 1 + }, + "Templates pod": { + "conditions": [ + { "label": "Templates", "type": "hasLabel", "value": true }, + { + "label": "Community template", + "type": "hasLabel", + "value": true + }, + { + "label": "Partial-import-export", + "type": "hasLabel", + "value": true + } + ], + "requires": 1 + }, + "Error Handling": { "conditions": [], "requires": 1 }, + "Workflows": { "conditions": [], "requires": 1 }, + "AI Pod": { "conditions": [], "requires": 1 } + } + }, + "root": "." + } + ], + "labels": { + "Tab Widget": { + "color": "e2c76c", + "name": "Tab Widget", + "description": "" + }, + "Dont merge": { + "color": "ADB39C", + "name": "Dont merge", + "description": "" + }, + "Epic": { + "color": "3E4B9E", + "name": "Epic", + "description": "A zenhub epic that describes a project" + }, + "Menu Button Widget": { + "color": "235708", + "name": "Menu Button Widget", + "description": "Issues related to Menu Button widget" + }, + "Checkbox Group widget": { + "color": "88054d", + "name": "Checkbox Group widget", + "description": "Issues related to Checkbox Group Widget" + }, + "Input Widget": { + "color": "ae65d8", + "name": "Input Widget", + "description": "" + }, + "Security": { "color": "99139C", "name": "Security", "description": "" }, + "QA": { "color": "e2ca68", "name": "QA", "description": "" }, + "Verified": { "color": "9bf416", "name": "Verified", "description": "" }, + "Wont Fix": { + "color": "ffffff", + "name": "Wont Fix", + "description": "This will not be worked on" + }, + "MySQL": { + "color": "c9ddc6", + "name": "MySQL", + "description": "Issues related to MySQL plugin" + }, + "Development": { + "color": "9F8A02", + "name": "Development", + "description": "" + }, + "Help Wanted": { + "color": "008672", + "name": "Help Wanted", + "description": "Extra attention is needed" + }, + "Home Page": { + "color": "9c0c8e", + "name": "Home Page", + "description": "Issues related to the application home page" + }, + "Rating Widget": { + "color": "235708", + "name": "Rating Widget", + "description": "Issues related to the rating widget" + }, + "Stat Box Widget": { + "color": "f1c9ce", + "name": "Stat Box Widget", + "description": "Issues related to stat box" + }, + "Enhancement": { + "color": "a2eeef", + "name": "Enhancement", + "description": "New feature or request" + }, + "Settings": { + "color": "f7ff60", + "name": "Settings", + "description": "organization, team & user settings" + }, + "Fork App": { + "color": "5369db", + "name": "Fork App", + "description": "Issues related to forking apps" + }, + "Container Widget": { + "color": "19AD0D", + "name": "Container Widget", + "description": "Container widget" + }, + "Papercut": { "color": "B562F6", "name": "Papercut", "description": "" }, + "Needs Design": { + "color": "bfd4f2", + "name": "Needs Design", + "description": "needs design or changes to design" + }, + "i18n": { + "color": "1799b0", + "name": "i18n", + "description": "Represents issues that need to be tackled to handle internationalization" + }, + "Rich Text Editor Widget": { + "color": "f72cac", + "name": "Rich Text Editor Widget", + "description": "" + }, + "Onboarding": { + "color": "d5794b", + "name": "Onboarding", + "description": "Issues related to onboarding new developers" + }, + "Pages": { + "color": "d7fd80", + "name": "Pages", + "description": "Issues related to configuring pages" + }, + "skip-changelog": { + "color": "06086F", + "name": "skip-changelog", + "description": "Adding this label to a PR prevents it from being listed in the changelog" + }, + "Low": { + "color": "79e53b", + "name": "Low", + "description": "An issue that is neither critical nor breaks a user flow" + }, + "potential-duplicate": { + "color": "d3cb2e", + "name": "potential-duplicate", + "description": "This label marks issues that are potential duplicates of already open issues" + }, + "Audio Widget": { + "color": "447B9A", + "name": "Audio Widget", + "description": "Issues related to Audio Widget" + }, + "Firestore": { + "color": "8078b0", + "name": "Firestore", + "description": "Issues related to the firestore Integration" + }, + "New Widget": { + "color": "be4cf2", + "name": "New Widget", + "description": "A request for a new widget" + }, + "Modal Widget": { + "color": "03846f", + "name": "Modal Widget", + "description": "" + }, + "UX Improvement": { + "color": "f4a089", + "name": "UX Improvement", + "description": "" + }, + "S3": { + "color": "8078b0", + "name": "S3", + "description": "Issues related to the S3 plugin" + }, + "Release Blocker": { + "color": "5756bf", + "name": "Release Blocker", + "description": "This issue must be resolved before the release" + }, + "safari": { + "color": "51C6AA", + "name": "safari", + "description": "Bugs seen on safari browser" + }, + "Example Apps": { + "color": "1799b0", + "name": "Example Apps", + "description": "Example apps created for new signups" + }, + "MultiSelect Widget": { + "color": "AB62D4", + "name": "MultiSelect Widget", + "description": "Issues related to MultiSelect Widget" + }, + "Widget Styling": { + "color": "905420", + "name": "Widget Styling", + "description": "all about widget styling" + }, + "Calendar Widget": { + "color": "8c6644", + "name": "Calendar Widget", + "description": "" + }, + "Website": { + "color": "151720", + "name": "Website", + "description": "Related to www.appsmith.com website" + }, + "Low effort": { + "color": "8B59F0", + "name": "Low effort", + "description": "Something that'll take a few days to build" + }, + "App Viewers Pod": { + "color": "cd8ef9", + "name": "App Viewers Pod", + "description": "This label assigns issues to the app viewers pod" + }, + "Checkbox Widget": { + "color": "88054d", + "name": "Checkbox Widget", + "description": "" + }, + "Spam": { "color": "620faf", "name": "Spam", "description": "" }, + "Voice Recorder Widget": { + "color": "85bc87", + "name": "Voice Recorder Widget", + "description": "" + }, + "Select Widget": { + "color": "0c669e", + "name": "Select Widget", + "description": "Select or dropdown widget" + }, + "Bug": { + "color": "d73a4a", + "name": "Bug", + "description": "Something isn't working" + }, + "Widget Validation": { + "color": "6990BC", + "name": "Widget Validation", + "description": "Issues related to widget property validation" + }, + "Generate Page": { + "color": "f14274", + "name": "Generate Page", + "description": "Issures related to page generation" + }, + "File Picker Widget": { + "color": "6ae4f2", + "name": "File Picker Widget", + "description": "" + }, + "snowflake": { + "color": "8078b0", + "name": "snowflake", + "description": "Issues related to the snowflake Integration" + }, + "Automation": { + "color": "CCAF60", + "name": "Automation", + "description": "" + }, + "hotfix": { "color": "BA3F1D", "name": "hotfix", "description": "" }, + "Team Managers Pod": { + "color": "bddb81", + "name": "Team Managers Pod", + "description": "Issues that team managers care about for the security and efficiency of their teams" + }, + "Import-Export-App": { + "color": "15076d", + "name": "Import-Export-App", + "description": "Issues related to importing and exporting apps" + }, + "High effort": { + "color": "A7E87B", + "name": "High effort", + "description": "Something that'll take more than a month to build" + }, + "Telemetry": { + "color": "bc70f9", + "name": "Telemetry", + "description": "Issues related to instrumenting appsmith" + }, + "Radio Widget": { + "color": "91ef15", + "name": "Radio Widget", + "description": "" + }, + "Omnibar": { + "color": "10b5ce", + "name": "Omnibar", + "description": "Issues related to the omnibar for navigation" + }, + "Button Widget": { + "color": "34efae", + "name": "Button Widget", + "description": "" + }, + "Switch widget": { + "color": "33A8CE", + "name": "Switch widget", + "description": "The switch widget" + }, + "Map Widget": { + "color": "7eef7a", + "name": "Map Widget", + "description": "" + }, + "Task": { + "color": "085630", + "name": "Task", + "description": "A simple Todo" + }, + "Design System": { + "color": "2958a4", + "name": "Design System", + "description": "Design system" + }, + "opera": { + "color": "C63F5B", + "name": "opera", + "description": "Any issues identified on the opera browser" + }, + "Login / Signup": { + "color": "771e69", + "name": "Login / Signup", + "description": "Authentication flows" + }, + "Image Widget": { + "color": "8de8ad", + "name": "Image Widget", + "description": "" + }, + "firefox": { "color": "6d56e2", "name": "firefox", "description": "" }, + "Property Pane": { + "color": "b356ff", + "name": "Property Pane", + "description": "Issues related to the behaviour of the property pane" + }, + "Deployment": { + "color": "93491f", + "name": "Deployment", + "description": "Installation process of appsmith" + }, + "Critical": { + "color": "9b1b28", + "name": "Critical", + "description": "This issue needs immediate attention. Drop everything else" + }, + "IDE": { + "color": "61b2ee", + "name": "IDE", + "description": "Issues related to the IDE" + }, + "Production": { + "color": "b60205", + "name": "Production", + "description": "" + }, + "Dependencies": { + "color": "0366d6", + "name": "Dependencies", + "description": "Pull requests that update a dependency file" + }, + "Google Sheets": { + "color": "8078b0", + "name": "Google Sheets", + "description": "Issues related to Google Sheets" + }, + "Icon Button Widget": { + "color": "D319CE", + "name": "Icon Button Widget", + "description": "Issues related to the icon button widget" + }, + "Mongo": { + "color": "8078b0", + "name": "Mongo", + "description": "Issues related to Mongo DB plugin" + }, + "Documentation": { + "color": "a8dff7", + "name": "Documentation", + "description": "Improvements or additions to documentation" + }, + "TestGap": { + "color": "f28253", + "name": "TestGap", + "description": "Issues identified for test plan improvement" + }, + "keyboard shortcut": { + "color": "0688B6", + "name": "keyboard shortcut", + "description": "" + }, + "Git Version Control": { + "color": "858172", + "name": "Git Version Control", + "description": "Issues related to version control" + }, + "Reopen": { "color": "897548", "name": "Reopen", "description": "" }, + "Redshift": { + "color": "8078b0", + "name": "Redshift", + "description": "Issues related to the redshift integration" + }, + "Date Picker Widget": { + "color": "ef1ce1", + "name": "Date Picker Widget", + "description": "" + }, + "Entity Explorer": { + "color": "a2e2f9", + "name": "Entity Explorer", + "description": "Issues related to navigation using the entity explorer" + }, + "JS Linting & Errors": { + "color": "E56AA5", + "name": "JS Linting & Errors", + "description": "Issues related to JS Linting and errors" + }, + "iFrame": { + "color": "3CD1DB", + "name": "iFrame", + "description": "Issues related to iFrame" + }, + "Stale": { "color": "ededed", "name": "Stale", "description": null }, + "Debugger": { + "color": "e79062", + "name": "Debugger", + "description": "Issues related to the debugger" + }, + "Quick effort": { + "color": "95ED65", + "name": "Quick effort", + "description": "Something that'll take a few hours to build" + }, + "Text Widget": { + "color": "d130d1", + "name": "Text Widget", + "description": "" + }, + "Video Widget": { + "color": "23dd4b", + "name": "Video Widget", + "description": "" + }, + "Datasources": { + "color": "5052f6", + "name": "Datasources", + "description": "Issues related to configuring datasource on appsmith" + }, + "error": { + "color": "B66773", + "name": "error", + "description": "All issues connected to error messages" + }, + "Form Widget": { + "color": "09ed77", + "name": "Form Widget", + "description": "" + }, + "Needs Triaging": { + "color": "e8b851", + "name": "Needs Triaging", + "description": "Needs attention from maintainers to triage" + }, + "Autocomplete": { + "color": "235708", + "name": "Autocomplete", + "description": "Issues related to the autocomplete" + }, + "hacktoberfest": { + "color": "0052cc", + "name": "hacktoberfest", + "description": "All issues that can be solved by the community during Hacktoberfest" + }, + "Medium effort": { + "color": "D31156", + "name": "Medium effort", + "description": "Something that'll take more than a week but less than a month to build" + }, + "Release": { "color": "57e5e0", "name": "Release", "description": "" }, + "High": { + "color": "c94d14", + "name": "High", + "description": "This issue blocks a user from building or impacts a lot of users" + }, + "UI Performance": { + "color": "1799b0", + "name": "UI Performance", + "description": "Issues related to UI performance" + }, + "UI Builders Pod": { + "color": "517fba", + "name": "UI Builders Pod", + "description": "Issues that UI Builders face using appsmith" + }, + "Deploy Preview": { + "color": "bfdadc", + "name": "Deploy Preview", + "description": "Issues found in Deploy Preview" + }, + "Needs Tests": { + "color": "8ee263", + "name": "Needs Tests", + "description": "Needs automated tests to assert a feature/bug fix" + }, + "Refactor": { + "color": "B96662", + "name": "Refactor", + "description": "needs refactoring of code" + }, + "Divider Widget": { + "color": "235708", + "name": "Divider Widget", + "description": "Issues related to the divider widget" + }, + "Table Widget": { + "color": "2eead1", + "name": "Table Widget", + "description": "" + }, + "Needs More Info": { + "color": "e54c10", + "name": "Needs More Info", + "description": "Needs additional information" + }, + "Good First Issue": { + "color": "7057ff", + "name": "Good First Issue", + "description": "Good for newcomers" + }, + "UI Improvement": { + "color": "9aeef4", + "name": "UI Improvement", + "description": "" + }, + "Backend": { + "color": "d4c5f9", + "name": "Backend", + "description": "This marks the issue or pull request to reference server code" + }, + "Frontend": { + "color": "87c7f2", + "name": "Frontend", + "description": "This label marks the issue or pull request to reference client code" + }, + "In App Comms": { + "name": "In App Comms", + "description": "Issues around communication with appsmith instances", + "color": "463cca" + }, + "Chart Widget": { + "color": "616ecc", + "name": "Chart Widget", + "description": "" + }, + "List Widget": { + "color": "8508A0", + "name": "List Widget", + "description": "Issues related to the list widget" + }, + "Duplicate": { + "color": "cfd3d7", + "name": "Duplicate", + "description": "This issue or pull request already exists" + }, + "JS Snippets": { + "color": "8d62d2", + "name": "JS Snippets", + "description": "issues related to JS Snippets" + }, + "Copy Paste": { + "name": "Copy Paste", + "description": "Issues related to copy paste", + "color": "b4f0a9" + }, + "Drag & Drop": { + "name": "Drag & Drop", + "description": "Issues related to the drag & drop experience", + "color": "92115a" + }, + "BE Coders Pod": { + "color": "5d9848", + "name": "BE Coders Pod", + "description": "Issues related to users writing code to fetch and update data" + }, + "FE Coders Pod": { + "color": "a7effc", + "name": "FE Coders Pod", + "description": "Issues related to users writing javascript in appsmith" + }, + "New Developers Pod": { + "color": "6310da", + "name": "New Developers Pod", + "description": "Issues that new developers face while exploring the IDE" + }, + "Sniping Mode": { + "name": "Sniping Mode", + "description": "Issues related to sniping mode", + "color": "6310da" + }, + "Redis": { + "name": "Redis", + "description": "Issues related to Redis", + "color": "8078b0" + }, + "New Datasource": { + "color": "60b14c", + "name": "New Datasource", + "description": "Requests for new datasources" + }, + "Evaluated Value": { + "name": "Evaluated Value", + "description": "Issues related to evaluated values", + "color": "39f6e7" + }, + "Undo/Redo": { + "name": "Undo/Redo", + "description": "Issues related to undo/redo", + "color": "f25880" + }, + "App Navigation": { + "name": "App Navigation", + "description": "Issues related to the topbar navigation and configuring it", + "color": "12b715" + }, + "Responsive Viewport": { + "color": "d12d2e", + "name": "Responsive Viewport", + "description": "Issues seen on different viewports like mobile" + }, + "Widgets Pane": { + "name": "Widgets Pane", + "description": "Issues related to the discovery and organisation of widgets", + "color": "ad5d78" + }, + "Invite users": { + "color": "1799b0", + "name": "Invite users", + "description": "Invite users flow and any associated actions" + }, + "View Mode": { + "color": "1799b0", + "name": "View Mode", + "description": "Issues related to the view mode" + }, + "User Education Pod": { + "name": "User Education Pod", + "description": "Issues related to user education", + "color": "1799b0" + }, + "Content": { + "name": "Content", + "description": "For content related topics i.e blogs, templates, videos", + "color": "a8dff7" + }, + "Embedding Apps": { + "name": "Embedding Apps", + "description": "Issues related to embedding", + "color": "26ef4f" + }, + "Slash Command": { + "name": "Slash Command", + "description": "Issues related to the slash command", + "color": "a0608e" + }, + "Widget Property": { + "name": "Widget Property", + "description": "Issues related to adding / modifying widget properties across widgets", + "color": "5e92cb" + }, + "Windows": { + "name": "Windows", + "description": "Issues related exclusively to Windows systems", + "color": "b4cb8a" + }, + "Old App Issues": { + "name": "Old App Issues", + "description": "Issues related to apps old apps a few weeks old and app issues in stale browser session", + "color": "87ab18" + }, + "Document Viewer Widget": { + "name": "Document Viewer Widget", + "description": "Issues related to Document Viewer Widget", + "color": "899d4b" + }, + "Radio Group Widget": { + "name": "Radio Group Widget", + "description": "Issues related to radio group widget", + "color": "b68495" + }, + "Super Admin": { + "name": "Super Admin", + "description": "Issues related to the super admin page", + "color": "aa95cf" + }, + "Postgres": { + "name": "Postgres", + "description": "Postgres related issues", + "color": "8078b0" + }, + "REST API plugin": { + "name": "REST API plugin", + "description": "REST API plugin related issues", + "color": "8078b0" + }, + "New JS Function": { + "name": "New JS Function", + "description": "Issues related to adding a JS Function", + "color": "8e8aa4" + }, + "Cannot Reproduce Issue": { + "color": "93c9cc", + "name": "Cannot Reproduce Issue", + "description": "Issues that cannot be reproduced" + }, + "Widget Grouping": { + "name": "Widget Grouping", + "description": "Issues related to Widget Grouping", + "color": "a49951" + }, + "K8s": { + "name": "K8s", + "description": "Kubernetes related issues", + "color": "5f318a" + }, + "Docker": { + "name": "Docker", + "description": "Issues related to docker", + "color": "89b808" + }, + "Camera Widget": { + "name": "Camera Widget", + "description": "Issues and enhancements related to camera widget", + "color": "e6038e" + }, + "SAAS Plugins": { + "name": "SAAS Plugins", + "description": "Issues related to SAAS Plugins", + "color": "ef9c9d" + }, + "JS Promises": { + "name": "JS Promises", + "description": "Issues related to promises", + "color": "d7771f" + }, + "OnPageLoad": { + "name": "OnPageLoad", + "description": "OnPageLoad issues on functions and queries", + "color": "50559d" + }, + "JS Usability": { + "name": "JS Usability", + "description": "usability issues with JS editor and JS elsewhere", + "color": "a302b0" + }, + "Currency Input Widget": { + "name": "Currency Input Widget", + "description": "Issues related to currency input widget", + "color": "b2164f" + }, + "TreeSelect": { + "name": "TreeSelect", + "description": "Issues related to TreeSelect Widget", + "color": "a1633e" + }, + "MultiTree Select Widget": { + "name": "MultiTree Select Widget", + "description": "Issues related to MultiTree Select Widget", + "color": "a1633e" + }, + "Welcome Screen": { + "name": "Welcome Screen", + "description": "Issues related to the welcome screen", + "color": "3897be" + }, + "Realtime Commenting": { + "color": "a70b86", + "name": "Realtime Commenting", + "description": "In-app communication between teams" + }, + "Phone Input Widget": { + "name": "Phone Input Widget", + "description": "Issues related to the Phone Input widget", + "color": "a70b86" + }, + "JSON Form": { + "name": "JSON Form", + "description": "Issue / features related to the JSON form wiget", + "color": "46b209" + }, + "All Widgets": { + "name": "All Widgets", + "description": "Issues related to all widgets", + "color": "972b36" + }, + "V1": { "name": "V1", "description": "V1", "color": "67ab2e" }, + "Reflow & Resize": { + "name": "Reflow & Resize", + "description": "All issues related to reflow and resize experience", + "color": "748a13" + }, + "App Theming": { + "name": "App Theming", + "description": "Items that are related to the App level theming controls epic", + "color": "905420" + }, + "SSO": { + "name": "SSO", + "description": "Issues, requests and enhancements around Single sign-on.", + "color": "bf019b" + }, + "Multi User Realtime": { + "name": "Multi User Realtime", + "description": "Issues related to multiple users using or editing an application", + "color": "e7b6ce" + }, + "Templates": { + "name": "Templates", + "description": "Issues related to templates", + "color": "b7e568" + }, + "Ready for design": { + "name": "Ready for design", + "description": "this issue is ready for design: it contains clear problem statements and other required information", + "color": "ebf442" + }, + "Support": { + "name": "Support", + "description": "Issues created by the A-force team to address user queries", + "color": "1740f3" + }, + "Button Group widget": { + "name": "Button Group widget", + "description": "Issue and enhancements related to the button group widget", + "color": "f17025" + }, + "GraphQL Plugin": { + "name": "GraphQL Plugin", + "description": "Issues related to GraphQL plugin", + "color": "8078b0" + }, + "DevOps Pod": { + "name": "DevOps Pod", + "description": "Issues related to devops", + "color": "d956c7" + }, + "medium": { + "name": "medium", + "description": "Issues that frustrate users due to poor UX", + "color": "23dfd9" + }, + "ArangoDB": { + "name": "ArangoDB", + "description": "Issues related to arangoDB", + "color": "8078b0" + }, + "Code Refactoring": { + "name": "Code Refactoring", + "description": "Issues related to code refactoring", + "color": "76310e" + }, + "Progress bar widget": { + "name": "Progress bar widget", + "description": "To track issues related to progress bar", + "color": "2d7abf" + }, + "Audio Recorder Widget": { + "name": "Audio Recorder Widget", + "description": "Issues related to Audio Recorder Widget", + "color": "9accef" + }, + "Airtable": { + "name": "Airtable", + "description": "Issues for Airtable", + "color": "60885f" + }, + "RBAC": { + "name": "RBAC", + "description": "Issues, requests and enhancements around RBAC.", + "color": "9211c3" + }, + "Canvas / Grid": { + "name": "Canvas / Grid", + "description": "Issues related to the canvas", + "color": "16b092" + }, + "Email Config": { + "name": "Email Config", + "description": "Issues related to configuring the email service", + "color": "2a21d1" + }, + "CURL": { + "name": "CURL", + "description": "Issues related to CURL impor", + "color": "60885f" + }, + "Canvas Zooms": { + "name": "Canvas Zooms", + "description": "Issues related to zooming the canvas", + "color": "e6038e" + }, + "business": { + "name": "business", + "description": "Features that will be a part of our business edition", + "color": "cd59eb" + }, + "Action Pod": { + "name": "Action Pod", + "description": "", + "color": "ee2e36" + }, + "AutomationGap1": { + "color": "a5e07c", + "name": "AutomationGap1", + "description": "Issues that needs automated tests" + }, + "A-Force11": { + "name": "A-Force11", + "description": "Issues raised by A-Force team", + "color": "d667b6" + }, + "Business Edition": { + "name": "Business Edition", + "description": "Features that will be a part of our business edition", + "color": "89bb6c" + }, + "storeValue": { + "name": "storeValue", + "description": "Issues related to the store value function", + "color": "5d3e66" + }, + "Tests": { "name": "Tests", "description": "test item", "color": "1c6990" }, + "DynamoDB": { + "name": "DynamoDB", + "description": "Issues that are related to DynamoDB should have this label", + "color": "60885f" + }, + "Design System Pod": { + "name": "Design System Pod", + "description": "Appsmith design system related issues", + "color": "706f03" + }, + "ABAC": { + "color": "e009a5", + "name": "ABAC", + "description": "User permissions and access controls" + }, + "Backup & Restore": { + "name": "Backup & Restore", + "description": "Issues related to backup and restore", + "color": "86874d" + }, + "Billing": { + "name": "Billing", + "description": "Billing infrastructure and flows for Business Edition and Trial users", + "color": "d2bc40" + }, + "Datatype issue": { + "name": "Datatype issue", + "description": "Issues that have risen because data types weren't handled", + "color": "60885f" + }, + "OAuth": { + "name": "OAuth", + "description": "OAuth related bugs or features", + "color": "60885f" + }, + "Table Widget V2": { + "name": "Table Widget V2", + "description": "Issues related to Table Widget V2", + "color": "3a7192" + }, + "IDE Navigation": { + "name": "IDE Navigation", + "description": "Issues/feature requests related to IDE navigation, and context switching", + "color": "bc0cba" + }, + "Query performance": { + "name": "Query performance", + "description": "Issues that have to do with lack in performance of query execution", + "color": "e4d966" + }, + "SAAS Manager App": { + "name": "SAAS Manager App", + "description": "Issues with the SAAS manager app", + "color": "d427db" + }, + "Twilio": { + "name": "Twilio", + "description": "Issues related to Twilio integration", + "color": "23ba8d" + }, + "Hubspot": { + "name": "Hubspot", + "description": "Issues related to Hubspot integration", + "color": "60885f" + }, + "Zendesk": { + "name": "Zendesk", + "description": "Issues related to Zendesk integration", + "color": "60885f" + }, + "Entity Refactor": { + "name": "Entity Refactor", + "description": "Issues related to refactor logic", + "color": "418fa4" + }, + "Branding": { + "name": "Branding", + "description": "All issues under branding and whitelabelling appsmith ecosystem", + "color": "7aaaf1" + }, + "Map Chart Widget": { + "name": "Map Chart Widget", + "description": "Issues related to Map Chart Widgets", + "color": "c8397f" + }, + "Product Catchup": { + "name": "Product Catchup", + "description": "Issues created in the product catchup", + "color": "29cd2c" + }, + "Framework Functions": { + "name": "Framework Functions", + "description": "Issues related to internal functions like showAlert(), navigateTo() etc...", + "color": "c25a09" + }, + "Frontend Libraries Upgrade": { + "name": "Frontend Libraries Upgrade", + "description": "Issues related to frontend libraries upgrade", + "color": "ede1fc" + }, + "Audit Logs": { + "name": "Audit Logs", + "description": "Audit trails to ensure data security", + "color": "f3fd62" + }, + "MsSQL": { + "name": "MsSQL", + "description": "Issues related to MsSQL plugin", + "color": "8078b0" + }, + "Data Platform Pod": { + "name": "Data Platform Pod", + "description": "Issues related to the underlying data platform", + "color": "3f8c3a" + }, + "Integrations Pod": { + "name": "Integrations Pod", + "description": "Issues related to a specific integration", + "color": "5dbbb1" + }, + "Datasource Environments": { + "name": "Datasource Environments", + "description": "Issues related to datasource environments", + "color": "bb7a14" + }, + "Elastic Search": { + "name": "Elastic Search", + "description": "Issues related to the elastic search datasource", + "color": "8078b0" + }, + "Core Query Execution": { + "color": "418fa4", + "name": "Core Query Execution", + "description": "Issues related to the execution of all queries" + }, + "Query Management": { + "name": "Query Management", + "description": "Issues related to the CRUD of actions or queries", + "color": "6a5b42" + }, + "Query Settings": { + "name": "Query Settings", + "description": "Issues related to the settings of all queries", + "color": "c7da7a" + }, + "Code Editor": { + "name": "Code Editor", + "description": "Issues related to the code editor", + "color": "4ca16e" + }, + "Query Forms": { + "color": "12b253", + "name": "Query Forms", + "description": "Isuses related to the query forms" + }, + "JS Objects": { + "color": "22962c", + "name": "JS Objects", + "description": "Issues related to JS Objects" + }, + "JS Evaluation": { + "color": "22962c", + "name": "JS Evaluation", + "description": "Issues related to JS evaluation on the platform" + }, + "SmartSubstitution": { + "name": "SmartSubstitution", + "description": "Issues related to Smart substitution of mustache bindings in queries", + "color": "e4d966" + }, + "Query Generation": { + "name": "Query Generation", + "description": "Issues related to query generation", + "color": "e4d966" + }, + "Suggested Widgets": { + "name": "Suggested Widgets", + "description": "Issues related to suggesting widgets based on query response", + "color": "e4d966" + }, + "Page load executions": { + "name": "Page load executions", + "description": "Issues related to page load execution", + "color": "5696b2" + }, + "Code Scanner Widget": { + "name": "Code Scanner Widget", + "description": "Issues related to code scanner widget", + "color": "9bc1a0" + }, + "Clean URLs": { + "name": "Clean URLs", + "description": "Issues related to clean URLs epic", + "color": "112623" + }, + "Widget keyboard accessibility": { + "name": "Widget keyboard accessibility", + "description": "All issues related to keyboard accessibility in widgets", + "color": "b626fd" + }, + "Connection pool": { + "name": "Connection pool", + "description": "issues to do with connection pooling of various plugins", + "color": "94fe36" + }, + "List Widget V2": { + "name": "List Widget V2", + "description": "Issues related to the list widget v2", + "color": "adaaf7" + }, + "Auto Height": { + "name": "Auto Height", + "description": "Issues related to dynamic height of widgets", + "color": "5149cf" + }, + "cypress_failed_test": { + "name": "cypress_failed_test", + "description": "Cypress failed tests", + "color": "4745d5" + }, + "Needs validation": { + "name": "Needs validation", + "description": "Needs problem validation before being picked up", + "color": "66673d" + }, + "Slider Widget": { + "name": "Slider Widget", + "description": "Issues raised for slider widgets.", + "color": "2eef5f" + }, + "Multitenancy": { + "name": "Multitenancy", + "description": "Support multitenancy within single appsmith instance", + "color": "8c49a9" + }, + "Git Pod": { + "name": "Git Pod", + "description": "Anything related to git sync", + "color": "2e5ba4" + }, + "Mobile Pod": { + "name": "Mobile Pod", + "description": "All issues related to mobile responsiveness", + "color": "6c97fd" + }, + "Responsive Widget": { + "name": "Responsive Widget", + "description": "All issues related to widget responsiveness", + "color": "d12d2e" + }, + "Responsive Canvas": { + "name": "Responsive Canvas", + "description": "All issues related to canvas responsiveness", + "color": "45a0a8" + }, + "Conversion Algorithm": { + "name": "Conversion Algorithm", + "description": "All issue related to converting app from fixed to flex mode & vice versa", + "color": "d12d2e" + }, + "Spacing": { + "name": "Spacing", + "description": "All issue related to spacing between widgets in auto layout", + "color": "d12d2e" + }, + "Browser specific": { + "name": "Browser specific", + "description": "All issue related to browser", + "color": "d12d2e" + }, + "Error Handling": { + "name": "Error Handling", + "description": "Issues related to error handling", + "color": "4e1872" + }, + "Performance infra": { + "name": "Performance infra", + "description": "all issue related to the performance infra", + "color": "8a60f6" + }, + "DSL Update": { + "name": "DSL Update", + "description": "Issues related to storing and updating the DSL", + "color": "e16cf3" + }, + "AST-frontend": { + "name": "AST-frontend", + "description": "Issues related to maintaining AST logic", + "color": "434a3a" + }, + "AST-backend": { + "name": "AST-backend", + "description": "Backend issues related to AST parsing", + "color": "c476eb" + }, + "MariaDB": { + "name": "MariaDB", + "description": "MariaDB datasource", + "color": "8428c3" + }, + "Billing & Usage Pod": { + "name": "Billing & Usage Pod", + "description": "Issues pertaining to licensing, billing, usage across self serve and enterprise customers", + "color": "256808" + }, + "ADS Component Issue": { + "name": "ADS Component Issue", + "description": "Issues which are caused due to ADS components", + "color": "d89119" + }, + "Regressed": { + "color": "723fd0", + "name": "Regressed", + "description": "Scenarios that were working before but have now regressed" + }, + "Needs RCA": { + "name": "Needs RCA", + "description": "a critical or high priority issue that needs an RCA", + "color": "2cc68f" + }, + "Custom JS Libraries": { + "name": "Custom JS Libraries", + "description": "Issues related to adding custom JS library", + "color": "bacb6d" + }, + "Integrations Pod General": { + "name": "Integrations Pod General", + "description": "Issues related to the Integrations Pod that don't fit into other tags.", + "color": "287823" + }, + "Performance Pod": { + "name": "Performance Pod", + "description": "All things related to Appsmith performance", + "color": "b5a25d" + }, + "Performance": { + "name": "Performance", + "description": "Issues related to performance", + "color": "9a18d7" + }, + "File upload issues": { + "name": "File upload issues", + "description": "Issues related to uploading any type of files from within Appsmith", + "color": "8154df" + }, + "Action Selector": { + "name": "Action Selector", + "description": "Issues related to action selector on the property pane", + "color": "2f9e20" + }, + "Widget design system": { + "name": "Widget design system", + "description": "", + "color": "11cc90" + }, + "Deploy App": { + "name": "Deploy App", + "description": "Issues related to app deployment", + "color": "6f6152" + }, + "Community Reported": { + "name": "Community Reported", + "description": "issues reported by community members", + "color": "1402e5" + }, + "JS Function execution": { + "name": "JS Function execution", + "description": "JS function execution", + "color": "7c2de1" + }, + "Self Serve": { + "name": "Self Serve", + "description": "For all issues related to self-serve flow for business edition", + "color": "4dacfc" + }, + "Self Serve 1.0": { + "name": "Self Serve 1.0", + "description": "For all issues related to v1 of the self serve project", + "color": "ae839e" + }, + "CE Instance": { + "name": "CE Instance", + "description": "For all issues relating to usage, licensing or billing on the CE instance", + "color": "d2bc40" + }, + "Customer Portal": { + "name": "Customer Portal", + "description": "For all tasks/issues pertaining to customer.appsmith.com", + "color": "d2bc40" + }, + "Cloud Services": { + "name": "Cloud Services", + "description": "For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing", + "color": "d2bc40" + }, + "Billing Integrations": { + "name": "Billing Integrations", + "description": "For all issues relating to 3P integrations Appsmith is using for billing & usage", + "color": "d2bc40" + }, + "One-click Binding": { + "name": "One-click Binding", + "description": "Issues related to the One click binding epic", + "color": "f1661c" + }, + "Airgap": { + "name": "Airgap", + "description": "Tickets related to supporting air-gapped Appsmith instances", + "color": "1cb294" + }, + "SMTP plugin": { + "name": "SMTP plugin", + "description": "Issues related to SMTP plugin", + "color": "541457" + }, + "AWS AMI": { + "name": "AWS AMI", + "description": "Issues Related to AWS AMI", + "color": "b44680" + }, + "Old widget version": { + "name": "Old widget version", + "description": "Use this label to raise issue specific only to an older version of a widget", + "color": "ff3814" + }, + "Enterprise Billing": { + "name": "Enterprise Billing", + "description": "To track all tasks/issues related to licensing & billing for enterprise customers", + "color": "14c156" + }, + "Appsmith Business Cloud": { + "name": "Appsmith Business Cloud", + "description": "Issues related to our business cloud offering", + "color": "89bb6c" + }, + "Oracle SQL DB": { + "name": "Oracle SQL DB", + "description": "Issues related to the Oracle plugin", + "color": "cbabcb" + }, + "Community Contributor": { + "name": "Community Contributor", + "description": "Meant to track issues that are assigned to external contributors", + "color": "149ab6" + }, + "widget vertical alignment": { + "name": "widget vertical alignment", + "description": "All issue related widget vertical alignment on the auto layout canvas", + "color": "d12d2e" + }, + "Observability": { + "name": "Observability", + "description": "Issues related to observability on the Appsmith instance", + "color": "dff913" + }, + "Checkbox Component": { + "name": "Checkbox Component", + "description": "This labels deals with checkbox component in wds package", + "color": "75a401" + }, + "In-app ramps": { + "name": "In-app ramps", + "description": "For all tasks/issues relating to adding in-app ramps in the community edition of the product", + "color": "8abae0" + }, + "Analytics Improvements": { + "name": "Analytics Improvements", + "description": "For all tasks focused on improving our overall analytics and fixing any issues ", + "color": "29b8ed" + }, + "WDS team": { "name": "WDS team", "description": "", "color": "8d675a" }, + "Enterprise Edition": { + "name": "Enterprise Edition", + "description": "Features that will be supported in Enterprise Edition only", + "color": "984f5e" + }, + "Query filter": { + "name": "Query filter", + "description": "Issues related to query filtering, e.g., WHERE clause", + "color": "a15134" + }, + "Keyboard accessibility ": { + "name": "Keyboard accessibility ", + "description": "All issue related to ADS component keyboard accessibility", + "color": "2ba696" + }, + "Toggle button": { + "name": "Toggle button", + "description": "All issue related to ADS toggle button", + "color": "edc47f" + }, + "1-click upgrade": { + "name": "1-click upgrade", + "description": "For all issues/tasks related to 1-click upgrade & downgrade project", + "color": "129082" + }, + "Feature Flagging": { + "name": "Feature Flagging", + "description": "Anything related feature flagging", + "color": "77443f" + }, + "SCIM": { + "name": "SCIM", + "description": "Label to collate our SCIM issues", + "color": "61a852" + }, + "ADS Category Token": { + "name": "ADS Category Token", + "description": "All issues related appsmith design system category tokens", + "color": "920961" + }, + "ADS Component Documentation": { + "name": "ADS Component Documentation", + "description": "All issues Appsmith design system component documentation", + "color": "64c46a" + }, + "ADS Migration": { + "name": "ADS Migration", + "description": "All issues related to Appsmith design system migration", + "color": "b082d6" + }, + "ADS Deduplication ": { + "name": "ADS Deduplication ", + "description": "Replacing component with ADS components", + "color": "b082d6" + }, + "ADS Revamp": { + "name": "ADS Revamp", + "description": "All issues related to ads revamp. ", + "color": "b082d6" + }, + "ADS Deduplication": { + "name": "ADS Deduplication", + "description": "Replacing component with ADS components", + "color": "b082d6" + }, + "ADS Grayscale": { + "name": "ADS Grayscale", + "description": "Support grayscale color changes", + "color": "b03577" + }, + "ADS Unit Test": { + "name": "ADS Unit Test", + "description": "All issue related ads unit cases ", + "color": "b082d6" + }, + "ADS Components": { + "name": "ADS Components", + "description": "All issues related ADS components", + "color": "b082d6" + }, + "Widget Discoverability": { + "name": "Widget Discoverability", + "description": "Issues related to Widget Discoverability", + "color": "7b55ce" + }, + "Widget setter method": { + "name": "Widget setter method", + "description": "Issues with widget property setters", + "color": "8dce87" + }, + "License": { + "name": "License", + "description": "For all issues/tasks related to licensing of appsmith-ee edition", + "color": "90ee98" + }, + "Templates pod": { + "name": "Templates pod", + "description": "Issues related to Templates", + "color": "b7e568" + }, + "Community template": { + "name": "Community template", + "description": "Label for development of community templates and its integration to platform", + "color": "8a0510" + }, + "DocumentDB": { + "name": "DocumentDB", + "description": "Issues related to support DocumentDB in Appsmith Data layer", + "color": "2c8b56" + }, + "Multiple Environments": { + "name": "Multiple Environments", + "description": "Issues or tasks related to multiple environments", + "color": "4e972b" + }, + "Platformization": { + "name": "Platformization", + "description": "Issues or tasks related to platformization of Appsmith codebase", + "color": "4e972b" + }, + "Activation - datasources": { + "name": "Activation - datasources", + "description": "issues related to activation projects", + "color": "7c7ace" + }, + "Partial-import-export": { + "name": "Partial-import-export", + "description": "Label for granular reusability.", + "color": "1e439c" + }, + "AI": { + "name": "AI", + "description": "All tasks related to AI", + "color": "69c7ca" + }, + "Custom environments": { + "name": "Custom environments", + "description": "Issues with creating or working with custom environments", + "color": "2137d6" + }, + "ADS Typography": { + "name": "ADS Typography", + "description": "All issue related typographical changes", + "color": "2dbe8d" + }, + "Auto Layout": { + "name": "Auto Layout", + "description": "Issues relates to auto layout", + "color": "92cf8c" + }, + "Heroku": { + "name": "Heroku", + "description": "Issues related to Heroku", + "color": "a81b69" + }, + "ADS Visual Styles": { + "name": "ADS Visual Styles", + "description": "All issues related to ADS visual styles", + "color": "d3da89" + }, + "ADS Component Design": { + "name": "ADS Component Design", + "description": "All issue related to component design", + "color": "5cc91e" + }, + "Modal Component": { + "name": "Modal Component", + "description": "All issue related to ads modal component", + "color": "ee63f3" + }, + "App setting": { + "name": "App setting", + "description": "Related to app settings panel within the app", + "color": "144206" + }, + "BE instance": { + "name": "BE instance", + "description": "For all issues related to license, billing on BE instance", + "color": "ae8f98" + }, + "Workflows": { + "name": "Workflows", + "description": "For all issues related to the Workflows feature", + "color": "ae2aa6" + }, + "Schema": { + "name": "Schema", + "description": "Issues related to database schema", + "color": "c470c2" + }, + "AI Pod": { + "name": "AI Pod", + "description": "Pod for all AI related tasks", + "color": "d18528" + }, + "Fixed layout": { + "name": "Fixed layout", + "description": "issues related to fixed layout", + "color": "b66681" + }, + "Anvil layout": { + "name": "Anvil layout", + "description": "issues related to the new layout system anvil", + "color": "722bf0" + }, + "New Deployment Mode": { + "name": "New Deployment Mode", + "description": "Support a new mode of deployment", + "color": "108033" + }, + "Custom widgets": { + "name": "Custom widgets", + "description": "For all issues related to the custom widget project", + "color": "c9db9c" + } + }, + "success": true +} diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b9f132ab48..1c758f51c3 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,12 +11,12 @@ > Add a TL;DR when description is extra long (helps content team) Fixes # (issue) + > if no issue exists, please create an issue and ask the maintainers about this first - Media -> A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video +> A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video ## Type of change @@ -27,26 +27,35 @@ Media - Breaking change (fix or feature that would cause existing functionality to not work as expected) - Chore (housekeeping or task changes that don't impact user perception) - This change requires a documentation update + > +## Testing -## How Has This Been Tested? -> Please describe the tests that you ran to verify your changes. Provide instructions, so we can reproduce. -> Please also list any relevant details for your test configuration. -> Delete anything that is not important +> -- Manual -- Jest -- Cypress +#### How Has This Been Tested? + +> Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. +> Delete anything that is not relevant + +- [ ] Manual +- [ ] JUnit +- [ ] Jest +- [ ] Cypress + > + +#### Test Plan -### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing + > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) - ## Checklist: + ### Dev activity + - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas @@ -56,8 +65,8 @@ Media - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag - #### QA activity: + - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members diff --git a/.github/workflows/ad-hoc-deploy-preview.yml b/.github/workflows/ad-hoc-deploy-preview.yml index 9d88c72e52..0bd2e530fa 100644 --- a/.github/workflows/ad-hoc-deploy-preview.yml +++ b/.github/workflows/ad-hoc-deploy-preview.yml @@ -31,7 +31,7 @@ jobs: "status": "IN_PROGRESS", "githubWorkflowId": "${{ github.run_id }}" }' - + server-build: name: server-build uses: ./.github/workflows/server-build.yml @@ -104,6 +104,12 @@ jobs: echo "Cleaning up the tar files" rm app/client/packages/rts/dist/rts-dist.tar + - name: Generate info.json + run: | + if [[ -f scripts/generate_info_json.sh ]]; then + scripts/generate_info_json.sh + fi + - name: Login to DockerHub uses: docker/login-action@v1 with: @@ -121,6 +127,7 @@ jobs: ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-dp:${{ github.event.inputs.sub-domain-name }} build-args: | APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com + BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:release outputs: imageHash: ${{ github.event.inputs.sub-domain-name }} @@ -190,4 +197,4 @@ jobs: "status": "FAILED" }' - + diff --git a/.github/workflows/appsmithctl.yml b/.github/workflows/appsmithctl.yml index 5270ff0f6b..d091308ee4 100644 --- a/.github/workflows/appsmithctl.yml +++ b/.github/workflows/appsmithctl.yml @@ -14,12 +14,12 @@ on: pull_request: branches: [release, master] paths: - - "deploy/docker/utils/**" + - "deploy/docker/fs/opt/appsmith/utils/**" # Change the working directory for all the jobs in this workflow defaults: run: - working-directory: deploy/docker/utils/ + working-directory: deploy/docker/fs/opt/appsmith/utils/ jobs: build: @@ -97,7 +97,7 @@ jobs: echo "appsmithctl_run_result=failed" >> $GITHUB_OUTPUT > ~/appsmithctl_run_result exit 1; - + # Set status = success - name: Save the status of the run run: echo "appsmithctl_run_result=success" >> $GITHUB_OUTPUT > ~/appsmithctl_run_result diff --git a/.github/workflows/build-client-server.yml b/.github/workflows/build-client-server.yml index d4123245a6..b86bdeedfd 100644 --- a/.github/workflows/build-client-server.yml +++ b/.github/workflows/build-client-server.yml @@ -186,45 +186,63 @@ jobs: run: shell: bash steps: - # Deleting the existing dir's if any - - name: Delete existing directories + - name: Setup node if: needs.ci-test-limited.result != 'success' - run: | - rm -f ~/failed_spec_ci - rm -f ~/combined_failed_spec_ci - - # Force store previous cypress dashboard url from cache - - name: Store the previous cypress dashboard url - if: success() - uses: actions/cache@v3 + uses: actions/setup-node@v3 with: - path: | - ~/cypress_url - key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }} - restore-keys: | - ${{ github.run_id }}-dashboard-url + node-version: 18 - - name: Print cypress dashboard url - id: dashboard_url - run: | - cypress_url=$(cat ~/cypress_url) - echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT - - # Download failed_spec list for all jobs - - uses: actions/download-artifact@v3 + - name: install pg if: needs.ci-test-limited.result != 'success' - id: download_ci + run: npm install pg + + - name: Fetch the failed specs + if: needs.ci-test-limited.result != 'success' + id: failed_specs + env: + DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + DB_USER: ${{ secrets.CYPRESS_DB_USER }} + DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + RUN_ID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + uses: actions/github-script@v6 with: - name: failed-spec-ci-${{github.run_attempt}} - path: ~/failed_spec_ci + script: | + const { Pool } = require("pg"); + const { DB_HOST, DB_NAME, DB_USER, DB_PWD, RUN_ID, ATTEMPT_NUMBER } = process.env + + const client = await new Pool({ + user: DB_USER, + host: DB_HOST, + database: DB_NAME, + password: DB_PWD, + port: 5432, + connectionTimeoutMillis: 60000, + }).connect(); + + const result = await client.query( + `SELECT DISTINCT name FROM public."specs" + WHERE "matrixId" IN + (SELECT id FROM public."matrix" + WHERE "attemptId" = ( + SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2 + ) + ) AND status = 'fail'`, + [RUN_ID, ATTEMPT_NUMBER], + ); + client.release(); + return result.rows.map((spec) => spec.name); # In case for any ci job failure, create combined failed spec - - name: "combine all specs for CI" + - name: combine all specs for CI + id: combine_ci if: needs.ci-test-limited.result != 'success' run: | - echo "Debugging: failed specs in ~/failed_spec_ci/failed_spec_ci*" - cat ~/failed_spec_ci/failed_spec_ci* - cat ~/failed_spec_ci/failed_spec_ci* | sort -u >> ~/combined_failed_spec_ci + failed_specs=$(echo ${{steps.failed_specs.outputs.result}} | sed 's/\[\|\]//g' | tr -d ' ' | tr ',' '\n') + while read -r line; do + echo "$line" >> ~/combined_failed_spec_ci + done <<< "$failed_specs" # Upload combined failed CI spec list to a file # This is done for debugging. @@ -258,9 +276,9 @@ jobs: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} body: | Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. - Cypress dashboard: Click here! + Cypress dashboard: Click here! The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}} - To know the list of identified flaky tests - Refer here + To know the list of identified flaky tests - Refer here - name: Add a comment on the PR when ci-test-limited is success if: needs.ci-test-limited.result == 'success' && needs.file-check.outputs.pr != '0' @@ -269,7 +287,7 @@ jobs: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} body: | Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. - Cypress dashboard url: Click here! + Cypress dashboard url: Click here! All cypress tests have passed 🎉🎉🎉 - name: Check ci-test-limited set status @@ -285,45 +303,63 @@ jobs: run: shell: bash steps: - # Deleting the existing dir's if any - - name: Delete existing directories + - name: Setup node if: needs.ci-test-limited-existing-docker-image.result != 'success' - run: | - rm -f ~/failed_spec_ci - rm -f ~/combined_failed_spec_ci - - # Force store previous cypress dashboard url from cache - - name: Store the previous cypress dashboard url - if: success() - uses: actions/cache@v3 + uses: actions/setup-node@v3 with: - path: | - ~/cypress_url - key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }} - restore-keys: | - ${{ github.run_id }}-dashboard-url + node-version: 18 - - name: Print cypress dashboard url - id: dashboard_url - run: | - cypress_url=$(cat ~/cypress_url) - echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT - - # Download failed_spec list for all jobs - - uses: actions/download-artifact@v3 + - name: install pg if: needs.ci-test-limited-existing-docker-image.result != 'success' - id: download_ci + run: npm install pg + + - name: Fetch the failed specs + if: needs.ci-test-limited-existing-docker-image.result != 'success' + id: failed_specs + env: + DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + DB_USER: ${{ secrets.CYPRESS_DB_USER }} + DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + RUN_ID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + uses: actions/github-script@v6 with: - name: failed-spec-ci-${{github.run_attempt}} - path: ~/failed_spec_ci + script: | + const { Pool } = require("pg"); + const { DB_HOST, DB_NAME, DB_USER, DB_PWD, RUN_ID, ATTEMPT_NUMBER } = process.env + + const client = await new Pool({ + user: DB_USER, + host: DB_HOST, + database: DB_NAME, + password: DB_PWD, + port: 5432, + connectionTimeoutMillis: 60000, + }).connect(); + + const result = await client.query( + `SELECT DISTINCT name FROM public."specs" + WHERE "matrixId" IN + (SELECT id FROM public."matrix" + WHERE "attemptId" = ( + SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2 + ) + ) AND status = 'fail'`, + [RUN_ID, ATTEMPT_NUMBER], + ); + client.release(); + return result.rows.map((spec) => spec.name); # In case for any ci job failure, create combined failed spec - - name: "combine all specs for CI" + - name: combine all specs for CI + id: combine_ci if: needs.ci-test-limited-existing-docker-image.result != 'success' run: | - echo "Debugging: failed specs in ~/failed_spec_ci/failed_spec_ci*" - cat ~/failed_spec_ci/failed_spec_ci* - cat ~/failed_spec_ci/failed_spec_ci* | sort -u >> ~/combined_failed_spec_ci + failed_specs=$(echo ${{steps.failed_specs.outputs.result}} | sed 's/\[\|\]//g' | tr -d ' ' | tr ',' '\n') + while read -r line; do + echo "$line" >> ~/combined_failed_spec_ci + done <<< "$failed_specs" # Upload combined failed CI spec list to a file # This is done for debugging. @@ -357,9 +393,9 @@ jobs: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} body: | Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. - Cypress dashboard: Click here! + Cypress dashboard: Click here! The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}} - To know the list of identified flaky tests - Refer here + To know the list of identified flaky tests - Refer here - name: Add a comment on the PR when ci-test-limited-existing-docker-image is success if: needs.ci-test-limited-existing-docker-image.result == 'success' && needs.file-check.outputs.pr != '0' @@ -368,7 +404,7 @@ jobs: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} body: | Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. - Cypress dashboard url: Click here! + Cypress dashboard url: Click here! All cypress tests have passed 🎉🎉🎉 - name: Check ci-test-limited-existing-docker-image set status diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 18a21ad158..a148254dd7 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -79,19 +79,27 @@ jobs: echo "Cleaning up the tar files" rm app/client/packages/rts/dist/rts-dist.tar + - name: Generate info.json + run: | + if [[ -f scripts/generate_info_json.sh ]]; then + scripts/generate_info_json.sh + fi + # We don't use Depot Docker builds because it's faster for local Docker images to be built locally. # It's slower and more expensive to build these Docker images on Depot and download it back to the CI node. - name: Build docker image if: steps.run_result.outputs.run_result != 'success' working-directory: "." run: | + set -o xtrace declare -a args - if [[ "${{ inputs.pr }}" != 0 ]]; then - args+=(--cache-from "${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:release") - fi if [[ "${{ inputs.pr }}" != 0 || "${{ github.ref_name }}" != master ]]; then args+=(--build-arg "APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com") + base_tag=release + else + base_tag=nightly fi + args+=(--build-arg "BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:$base_tag") docker build -t cicontainer "${args[@]}" . # Saving the docker image to tar file diff --git a/.github/workflows/ci-sanity.yml b/.github/workflows/ci-sanity.yml index 41ed300726..32713877cb 100644 --- a/.github/workflows/ci-sanity.yml +++ b/.github/workflows/ci-sanity.yml @@ -92,7 +92,7 @@ jobs: key: ${{ github.run_id }}-failed_spec_ci_sanity-${{ github.job }} restore-keys: | ${{ github.run_id }}-failed_spec_ci_sanity-${{ github.job }} - + # failed_spec_env will contain list of all failed specs # We are using environment variable instead of regular to support multiline - name: Get failed_spec @@ -151,15 +151,15 @@ jobs: cicontainer - name: Setup MSSQL & Arango docker containers - working-directory : app/client/cypress - run : | + working-directory: app/client/cypress + run: | docker run --name=mssqldb -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Root@123" -p 1433:1433 -d mcr.microsoft.com/azure-sql-edge docker run --name arangodb -e ARANGO_USERNAME=root -e ARANGO_ROOT_PASSWORD=Arango -p 8529:8529 -d arangodb - # docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf" - # docker restart mssqldb - # sudo ufw allow 1433/tcp - # docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql - # docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql + # docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf" + # docker restart mssqldb + # sudo ufw allow 1433/tcp + # docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql + # docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql - name: Use Node.js if: steps.run_result.outputs.run_result != 'success' @@ -179,48 +179,6 @@ jobs: - name: Setting up the cypress tests if: steps.run_result.outputs.run_result != 'success' shell: bash - env: - APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} - APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} - CYPRESS_URL: ${{ secrets.CYPRESS_URL }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - POSTGRES_PASSWORD: postgres run: | cd app/client chmod a+x ./cypress/setup-test-ci.sh @@ -253,6 +211,10 @@ jobs: CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} @@ -272,6 +234,8 @@ jobs: CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} CYPRESS_EXCLUDE_TAGS: "airgap" CYPRESS_AIRGAPPED: false APPSMITH_DISABLE_TELEMETRY: true @@ -313,6 +277,10 @@ jobs: CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} @@ -332,6 +300,8 @@ jobs: CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} CYPRESS_EXCLUDE_TAGS: "airgap" CYPRESS_AIRGAPPED: false APPSMITH_DISABLE_TELEMETRY: true diff --git a/.github/workflows/ci-smoke.yml b/.github/workflows/ci-smoke.yml index 5e57c8f5aa..a5e0135ff1 100644 --- a/.github/workflows/ci-smoke.yml +++ b/.github/workflows/ci-smoke.yml @@ -92,7 +92,7 @@ jobs: key: ${{ github.run_id }}-failed_spec_ci_smoke-${{ github.job }} restore-keys: | ${{ github.run_id }}-failed_spec_ci_smoke-${{ github.job }} - + # failed_spec_env will contain list of all failed specs # We are using environment variable instead of regular to support multiline - name: Get failed_spec @@ -151,15 +151,15 @@ jobs: cicontainer - name: Setup MSSQL & Arango docker containers - working-directory : app/client/cypress - run : | + working-directory: app/client/cypress + run: | docker run --name=mssqldb -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Root@123" -p 1433:1433 -d mcr.microsoft.com/azure-sql-edge docker run --name arangodb -e ARANGO_USERNAME=root -e ARANGO_ROOT_PASSWORD=Arango -p 8529:8529 -d arangodb - # docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf" - # docker restart mssqldb - # sudo ufw allow 1433/tcp - # docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql - # docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql + # docker exec -i mssqldb /bin/bash -c "echo -e '[mysqld]\ntcpport=1433\ntcpnodelay=1' >> /var/opt/mssql/mssql.conf" + # docker restart mssqldb + # sudo ufw allow 1433/tcp + # docker cp init-mssql-dump-for-test.sql mssqldb:var/init-mssql-dump-for-test.sql + # docker exec -i mssqldb /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P Root@123 -i /var/init-mssql-dump-for-test.sql - name: Use Node.js if: steps.run_result.outputs.run_result != 'success' @@ -179,48 +179,6 @@ jobs: - name: Setting up the cypress tests if: steps.run_result.outputs.run_result != 'success' shell: bash - env: - APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} - APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} - CYPRESS_URL: ${{ secrets.CYPRESS_URL }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - POSTGRES_PASSWORD: postgres run: | cd app/client chmod a+x ./cypress/setup-test-ci.sh @@ -253,6 +211,10 @@ jobs: CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} @@ -272,6 +234,8 @@ jobs: CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} CYPRESS_EXCLUDE_TAGS: "airgap" CYPRESS_AIRGAPPED: false APPSMITH_DISABLE_TELEMETRY: true @@ -313,6 +277,10 @@ jobs: CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} @@ -332,6 +300,8 @@ jobs: CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} CYPRESS_EXCLUDE_TAGS: "airgap" CYPRESS_AIRGAPPED: false APPSMITH_DISABLE_TELEMETRY: true diff --git a/.github/workflows/ci-test-custom-script.yml b/.github/workflows/ci-test-custom-script.yml index 001a17c9e5..3c2f74149d 100644 --- a/.github/workflows/ci-test-custom-script.yml +++ b/.github/workflows/ci-test-custom-script.yml @@ -24,7 +24,69 @@ jobs: strategy: fail-fast: false matrix: - job: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59] + job: + [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + ] # Service containers to run with this job. Required for running tests services: @@ -44,6 +106,12 @@ jobs: - name: Set up Depot CLI uses: depot/setup-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + # Check out merge commit - name: Fork based /ok-to-test checkout if: inputs.pr != 0 @@ -80,39 +148,17 @@ jobs: run: | run_result_env=$(cat ~/run_result) echo "run_result=$run_result_env" >> $GITHUB_OUTPUT + if [[ "$run_result_env" == "failedtest" ]]; then + echo "rerun=true" >> $GITHUB_OUTPUT + else + echo "rerun=false" >> $GITHUB_OUTPUT + fi - name: Dump steps context env: STEPS_CONTEXT: ${{ toJson(steps) }} run: echo "$STEPS_CONTEXT" - # In case this is second attempt try restoring failed tests - - if : steps.run_result.outputs.run_result == 'failedtest' - run: echo "failed_spec_artifact=failed-spec-ci-$((${{github.run_attempt}}-1))" >> $GITHUB_ENV - - name: Restore the previous failed combine result - if: steps.run_result.outputs.run_result == 'failedtest' - uses: actions/download-artifact@v3 - with: - name: ${{ env.failed_spec_artifact }} - path: ~/failed_spec_ci - - # failed_spec_env will contain list of all failed specs - # We are using environment variable instead of regular to support multiline - - name: Get failed_spec - id: failed_spec - if: steps.run_result.outputs.run_result == 'failedtest' - working-directory: app/client - run: | - failed_spec_env="" - while IFS= read -r line - do - spec_name=$(echo $line | awk -F'/' '{print $NF}') - failed_spec=$(find . -name $spec_name | sed 's|./||') - failed_spec_env="$failed_spec_env,$failed_spec" - done < ~/failed_spec_ci/failed_spec_ci-${{ matrix.job }} - failed_spec_env=${failed_spec_env#,} - echo "failed_spec_env=$failed_spec_env" >> $GITHUB_ENV - - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' run: echo "Starting full run" && exit 0 @@ -148,12 +194,43 @@ jobs: docker run --name test-event-driver -d -p 22:22 -p 5001:5001 -p 3306:3306 \ -p 5432:5432 -p 28017:27017 -p 25:25 -p 5000:5000 -p 3001:3000 -p 6001:6001 --privileged --pid=host --ipc=host --volume /:/host -v ~/git-server/keys:/git-server/keys \ -v ~/git-server/repos:/git-server/repos appsmith/test-event-driver:latest + docker run --name cloud-services -d -p 8000:80 -p 8090:8090 \ + --privileged --pid=host --ipc=host --add-host=host.docker.internal:host-gateway\ + -e APPSMITH_CLOUD_SERVICES_MONGODB_URI=mongodb://host.docker.internal:27017 \ + -e APPSMITH_CLOUD_SERVICES_MONGODB_DATABASE=cs \ + -e APPSMITH_CLOUD_SERVICES_MONGODB_AUTH_DATABASE=admin \ + -e APPSMITH_REDIS_URL=redis://host.docker.internal:6379/ \ + -e APPSMITH_APPS_API_KEY=dummy-api-key \ + -e APPSMITH_REMOTE_API_KEY=dummy-api-key \ + -e APPSMITH_GITHUB_API_KEY=dummy-appsmith-gh-api-key \ + -e APPSMITH_JWT_SECRET=appsmith-cloud-services-jwt-secret-dummy-key \ + -e APPSMITH_ENCRYPTION_SALT=encryption-salt \ + -e APPSMITH_ENCRYPTION_PASSWORD=encryption-password \ + -e APPSMITH_CLOUD_SERVICES_URL=https://cs-dev.appsmith.com \ + -e APPSMITH_CUSTOMER_PORTAL_URL=https://dev.appsmith.com \ + -e APPSMITH_CLOUD_SERVICES_BASE_URL=https://cs-dev.appsmith.com \ + -e APPSMITH_CLOUD_SERVER_BASE_URL=https://release.app.appsmith.com \ + -e AUTH0_ISSUER_URL=https://login.release-customer.appsmith.com/ \ + -e AUTH0_CLIENT_ID=dummy-client-id \ + -e AUTH0_CLIENT_SECRET=dummy-secret-id \ + -e AUTH0_AUDIENCE_URL=https://login.local-customer.appsmith.com/ \ + -e CLOUDSERVICES_URL=cs-dev.appsmith.com \ + -e CUSTOMER_URL=dev.appsmith.com \ + -e ENTERPRISE_USER_NAME=ent-user@appsmith.com \ + -e ENTERPRISE_USER_PASSWORD=ent_user_password \ + -e ENTERPRISE_ADMIN_NAME=ent-admin@appsmith.com \ + -e ENTERPRISE_ADMIN_PASSWORD=ent_admin_password \ + -e FLAGSMITH_URL=http://host.docker.internal:5001/flagsmith \ + -e FLAGSMITH_SERVER_KEY=dummykey \ + -e FLAGSMITH_SERVER_KEY_BUSINESS_FEATURES=dummykeybusinessfeatures \ + appsmith/cloud-services:release cd cicontainerlocal docker run -d --name appsmith -p 80:80 -p 9001:9001 \ -v "$PWD/stacks:/appsmith-stacks" \ -e APPSMITH_DISABLE_TELEMETRY=true \ -e APPSMITH_INTERCOM_APP_ID=DUMMY_VALUE \ -e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \ + -e APPSMITH_CLOUD_SERVICES_SIGNATURE_BASE_URL=http://host.docker.internal:8090 \ --add-host=host.docker.internal:host-gateway --add-host=api.segment.io:host-gateway --add-host=t.appsmith.com:host-gateway \ cicontainer @@ -185,49 +262,6 @@ jobs: - name: Setting up the cypress tests if: steps.run_result.outputs.run_result != 'success' shell: bash - env: - APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} - APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - POSTGRES_PASSWORD: postgres - CYPRESS_VERIFY_TIMEOUT: 100000 run: | cd app/client chmod a+x ./cypress/setup-test-ci.sh @@ -239,69 +273,50 @@ jobs: - run: | echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV - - name: Run the cypress test - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' - id: cypress_test - uses: cypress-io/github-action@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} - CYPRESS_VERIFY_TIMEOUT: 100000 - TOTAL_RUNNERS: ${{ strategy.job-total }} - THIS_RUNNER: ${{ strategy.job-index }} - CYPRESS_SPEC_PATTERN: "cypress/e2e/**/**/*" - CYPRESS_ENV: "NODE_ENV=development" - CYPRESS_CONFIG_FILE: cypress_ci_custom.config.ts - CYPRESS_HEADLESS: "true" - CYPRESS_BROWSER: ${{ env.BROWSER_PATH }} - with: - install: false - working-directory: app/client - command: yarn ts-node --require esm cypress/cypress-split.ts + - name: Save Git values + # pass env variables from this step to other steps + # using GitHub Actions environment file + # https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#environment-files + run: | + PR_NUMBER=${{ inputs.pr }} + echo COMMIT_INFO_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV + echo COMMIT_INFO_MESSAGE=OkToTest run on PR# ${{ inputs.pr }} >> $GITHUB_ENV + echo COMMIT_INFO_EMAIL=$(git show -s --pretty=%ae) >> $GITHUB_ENV + echo COMMIT_INFO_AUTHOR=$(git show -s --pretty=%an) >> $GITHUB_ENV + echo COMMIT_INFO_SHA=$(git show -s --pretty=%H) >> $GITHUB_ENV + echo COMMIT_INFO_TIMESTAMP=$(git show -s --pretty=%ct) >> $GITHUB_ENV + echo COMMIT_INFO_REMOTE=$(git config --get remote.origin.url) >> $GITHUB_ENV + # delete the .git folder afterwords to use the environment values + rm -rf .git - # In case of second attempt only run failed specs - - name: Run the cypress test with failed tests - if: steps.run_result.outputs.run_result == 'failedtest' - id: cypress_test_failedtest - uses: cypress-io/github-action@v5 + - name: Show Git values + run: | + echo Branch $COMMIT_INFO_BRANCH + echo Message $COMMIT_INFO_MESSAGE + echo Email $COMMIT_INFO_EMAIL + echo Author $COMMIT_INFO_AUTHOR + echo SHA $COMMIT_INFO_SHA + echo Timestamp $COMMIT_INFO_TIMESTAMP + echo Remote $COMMIT_INFO_REMOTE + + - name: Set Commit Message + env: + EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }} + run: | + eventCommit=$(echo ${{env.EVENT_COMMITS}} | sed "s/'//g") + if [[ ${{ inputs.pr }} -ne 0 ]]; then + echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE }}" >> $GITHUB_ENV + else + if [[ '$eventCommit' == 'null' ]]; then + echo "COMMIT_INFO_MESSAGE=$(echo ${{ github.event_name }} | perl -pe 's/(^|_)./uc($&)/ge;s/_//g')" >> $GITHUB_ENV + echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE}} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV + else + echo "COMMIT_INFO_MESSAGE=$(echo "$eventCommit" | awk -F '\\\\n' '{print $1}' | sed 's/^"//;s/"$//')" >> $GITHUB_ENV + fi + fi + + - name: Run the cypress test + uses: cypress-io/github-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} @@ -318,6 +333,10 @@ jobs: CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} @@ -338,19 +357,47 @@ jobs: CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} CYPRESS_EXCLUDE_TAGS: "airgap" CYPRESS_AIRGAPPED: false APPSMITH_DISABLE_TELEMETRY: true APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + POSTGRES_PASSWORD: postgres + CYPRESS_VERIFY_TIMEOUT: 100000 COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} - CYPRESS_ENV: "NODE_ENV=development" - CYPRESS_CONFIG_FILE: cypress_ci.config.ts - CYPRESS_HEADLESS: "true" - CYPRESS_BROWSER: ${{ env.BROWSER_PATH }} + THIS_RUNNER: ${{ strategy.job-index }} + RUNID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + REPOSITORY: ${{ github.repository }} + COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }} + TAG: ${{ github.event_name }} + BRANCH: ${{ env.COMMIT_INFO_BRANCH }} + CYPRESS_RERUN: ${{steps.run_result.outputs.rerun}} + CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }} + CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }} + CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }} with: + browser: ${{ env.BROWSER_PATH }} install: false + config-file: cypress_ci_custom.config.ts working-directory: app/client - command: yarn cypress run --browser ${{ env.BROWSER_PATH }} --config-file cypress_ci_custom.config.ts --spec ${{ env.failed_spec_env }} + env: "NODE_ENV=development" + + - name: Trim number of cypress log files + if: failure() + run: | + find ${{ github.workspace }}/app/client/cypress/cypress-logs -name '*.json' -type f | tail -n +11 | xargs -I {} rm -- {} + + - name: Upload failed test cypress logs artifact + if: failure() + uses: actions/upload-artifact@v3 + with: + name: cypress-console-logs + path: ${{ github.workspace }}/app/client/cypress/cypress-logs - name: Collect CI container logs if: failure() @@ -368,13 +415,13 @@ jobs: path: ~/dockerlogs - name: Rename reports - if: always() + if: failure() run: | mkdir -p ~/results mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }} - name: Upload cypress report - if: always() + if: failure() uses: actions/upload-artifact@v3 with: name: results-${{github.run_attempt}} @@ -387,28 +434,6 @@ jobs: echo "run_result=failedtest" >> $GITHUB_OUTPUT echo "failedtest" > ~/run_result - # Create a directory ~/failed_spec_ci and add a dummy file - # This will ensure upload and download steps are successful - - name: Create directory for failed tests - if: always() - run: | - mkdir -p ~/failed_spec_ci-${{github.run_attempt}} - - # add list failed tests to a file - - name: In case of test failures copy them to a file - if: failure() - run: | - cd ${{ github.workspace }}/app/client/cypress/ - find screenshots -type f \( -iname "*\(attempt 2\).png" -o -iname "*before all hook*" -o -iname "*after all hook*" \) | sed 's/screenshots/cypress\/e2e/g'| sed 's:/[^/]*$::' | sort -u > ~/failed_spec_ci-${{github.run_attempt}}/failed_spec_ci-${{ matrix.job }} - - # Upload failed test list using common path for all matrix job - - name: Upload failed test list artifact - if: failure() - uses: actions/upload-artifact@v3 - with: - name: failed-spec-ci-${{github.run_attempt}} - path: ~/failed_spec_ci-${{github.run_attempt}} - # Force store previous run result to cache - name: Store the previous run result if: failure() @@ -418,16 +443,6 @@ jobs: ~/run_result key: ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} - - name: get cypress url dashboard url - id: dashboard_url - if: always() - run: | - if [[ "${{steps.run_result.outputs.run_result }}" != "success" && "${{steps.run_result.outputs.run_result }}" != "failedtest" ]]; then - echo "" >> ~/cypress_url - elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then - echo "" >> ~/cypress_url - fi - # Force store previous run result to cache - name: Store the previous run result if: success() diff --git a/.github/workflows/ci-test-hosted.yml b/.github/workflows/ci-test-hosted.yml index 47d4008ba3..18486b6437 100644 --- a/.github/workflows/ci-test-hosted.yml +++ b/.github/workflows/ci-test-hosted.yml @@ -86,36 +86,17 @@ jobs: run: | run_result_env=$(cat ~/run_result) echo "run_result=$run_result_env" >> $GITHUB_OUTPUT + if [[ "$run_result_env" == "failedtest" ]]; then + echo "rerun=true" >> $GITHUB_OUTPUT + else + echo "rerun=false" >> $GITHUB_OUTPUT + fi - name: Dump steps context env: STEPS_CONTEXT: ${{ toJson(steps) }} run: echo "$STEPS_CONTEXT" - # In case this is second attempt try restoring failed tests - - name: Restore the previous failed combine result - if: steps.run_result.outputs.run_result == 'failedtest' - uses: actions/download-artifact@v3 - with: - name: failed_spec_ci - path: ~/failed_spec_ci - - # failed_spec_env will contain list of all failed specs - # We are using environment variable instead of regular to support multiline - - name: Get failed_spec - id: failed_spec - if: steps.run_result.outputs.run_result == 'failedtest' - working-directory: app/client - run: | - echo "failed_spec_env<> $GITHUB_ENV - while IFS= read -r line - do - spec_name=$(echo $line | awk -F'/' '{print $NF}') - failed_spec_env=$(find . -name $spec_name | sed 's|./||') - echo "$failed_spec_env" >> $GITHUB_ENV - done < ~/failed_spec_ci/failed_spec_ci - echo "EOF" >> $GITHUB_ENV - - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' run: echo "Starting full run" && exit 0 @@ -153,50 +134,6 @@ jobs: - name: Setting up the cypress tests if: steps.run_result.outputs.run_result != 'success' shell: bash - env: - APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} - APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} - CYPRESS_URL: ${{ secrets.CYPRESS_URL }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - POSTGRES_PASSWORD: postgres - CYPRESS_VERIFY_TIMEOUT: 100000 run: | cd app/client chmod a+x ./cypress/setup-test-ci.sh @@ -208,12 +145,6 @@ jobs: - run: | echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV - # - name: Set Pull Request Title - # env: - # EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }} - # run: | - # echo "${{ env.EVENT_COMMITS }}" | awk -F '\\\\n' '{print $1}' - - name: Save Git values # pass env variables from this step to other steps # using GitHub Actions environment file @@ -245,19 +176,15 @@ jobs: EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }} run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then - echo "COMMIT_INFO_MESSAGE=Scheduled workflow run for gsheet tests" >> $GITHUB_ENV + echo "COMMIT_INFO_MESSAGE=Scheduled run for Hosted tests" >> $GITHUB_ENV else - echo "COMMIT_INFO_MESSAGE=Manual workflow run for gsheet tests" >> $GITHUB_ENV + echo "COMMIT_INFO_MESSAGE=Manual workflow run for Hosted tests" >> $GITHUB_ENV fi - name: Run the cypress test - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' - id: cypress_test - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} @@ -272,6 +199,10 @@ jobs: CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} @@ -292,87 +223,54 @@ jobs: CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} CYPRESS_EXCLUDE_TAGS: "airgap" CYPRESS_AIRGAPPED: false APPSMITH_DISABLE_TELEMETRY: true APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} CYPRESS_VERIFY_TIMEOUT: 100000 + RUNID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + REPOSITORY: ${{ github.repository }} + COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }} + TAG: ${{ github.event_name }} + BRANCH: ${{ env.COMMIT_INFO_BRANCH }} + THIS_RUNNER: ${{ strategy.job-index }} + TOTAL_RUNNERS: ${{ strategy.job-total }} + CYPRESS_RERUN: ${{steps.run_result.outputs.rerun}} + CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }} + CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }} + CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }} with: - browser: ${{ env.BROWSER_PATH }} - record: true install: false - parallel: true config-file: cypress_ci_hosted.config.ts - group: "Chrome-Fat Container tests" - spec: | - cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts - cypress/e2e/GSheet/**/**/* working-directory: app/client - # tag will be either "push" or "pull_request" - tag: ${{ github.event_name }} env: "NODE_ENV=development" - # In case of second attempt only run failed specs - - name: Run the cypress test with failed tests - if: steps.run_result.outputs.run_result == 'failedtest' - id: cypress_test_failedtest - uses: cypress-io/github-action@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} + - name: Rename reports + if: failure() + run: | + mkdir -p ~/results + mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }} + + - name: Upload cypress report + if: failure() + uses: actions/upload-artifact@v3 with: - browser: ${{ env.BROWSER_PATH }} - record: true - install: false - parallel: true - config-file: cypress_ci_hosted.config.ts - group: "Chrome-Fat Container tests" - spec: ${{ env.failed_spec_env }} - working-directory: app/client - # tag will be either "push" or "pull_request" - tag: ${{ github.event_name }} - env: "NODE_ENV=development" + name: results-${{github.run_attempt}} + path: ~/results + + - name: Upload cypress snapshots + if: failure() + uses: actions/upload-artifact@v3 + with: + name: snapshots + path: ${{ github.workspace }}/app/client/cypress/snapshots # Set status = failedtest - name: Set fail if there are test failures @@ -382,27 +280,6 @@ jobs: echo "run_result=failedtest" >> $GITHUB_OUTPUT echo "failedtest" > ~/run_result - # add list failed tests to a file - - name: In case of test failures copy them to a file - if: failure() - run: | - cd ${{ github.workspace }}/app/client/cypress/ - find screenshots -type f \( -iname "*\(attempt 2\).png" -o -iname "*before all hook*" -o -iname "*after all hook*" \) | sed 's/screenshots/cypress\/e2e/g'| sed 's:/[^/]*$::' | sort -u > ~/failed_spec_ci - - # reset the failed_spec_ci file in case of success - - name: In case of test success reset the failed_spec_ci file - if: success() - run: | - touch ~/failed_spec_ci - - # Upload failed test list using common path for all matrix job - - name: Upload failed test list artifact - if: always() - uses: actions/upload-artifact@v3 - with: - name: failed_spec_ci - path: ~/failed_spec_ci - # Force store previous run result to cache - name: Store the previous run result if: failure() @@ -411,16 +288,6 @@ jobs: path: | ~/run_result key: ${{ github.run_id }}-${{ github.job }} - - - name: get cypress url dashboard url - id: dashboard_url - if: always() - run: | - if [[ "${{steps.run_result.outputs.run_result }}" != "success" && "${{steps.run_result.outputs.run_result }}" != "failedtest" ]]; then - echo "url=${{ steps.cypress_test.outputs.resultsUrl }}" >> $GITHUB_OUTPUT - elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then - echo "url=${{ steps.cypress_test_failedtest.outputs.resultsUrl }}" >> $GITHUB_OUTPUT - fi - name: Generate slack message continue-on-error: true @@ -428,11 +295,13 @@ jobs: id: slack_notification run: | if [[ "${{ steps.test_status.outputs.run_result }}" == "failedtest" ]]; then - echo "slack_message=There are test failures in the run. Please check the <${{ steps.dashboard_url.outputs.url }}|Cypress dashboard> for more details." >> $GITHUB_OUTPUT + echo "slack_message=There are test failures in the run. Cypress Dashboard: " >> $GITHUB_OUTPUT echo "slack_color=#FF0000" >> $GITHUB_OUTPUT + echo "slack_icon=:parachute:" >> $GITHUB_OUTPUT else - echo "slack_message=All tests passed successfully :tada: . Cypress Dashboard: <${{ steps.dashboard_url.outputs.url }}|Click here!>" >> $GITHUB_OUTPUT + echo "slack_message=All tests passed successfully :tada: . Cypress Dashboard: " >> $GITHUB_OUTPUT echo "slack_color=#00FF00" >> $GITHUB_OUTPUT + echo "slack_icon=:eight_spoked_asterisk:" >> $GITHUB_OUTPUT fi - name: Slack Notification @@ -442,21 +311,13 @@ jobs: env: SLACK_CHANNEL: cypresspushworkflow SLACK_COLOR: ${{steps.slack_notification.outputs.slack_color}} - SLACK_ICON_EMOJI: ':bell:' + SLACK_ICON_EMOJI: ${{steps.slack_notification.outputs.slack_icon}} SLACK_MESSAGE: ${{steps.slack_notification.outputs.slack_message}} - SLACK_TITLE: 'Result:' - SLACK_USERNAME: Cloud-Hosted Tests + SLACK_TITLE: "Result:" + SLACK_USERNAME: Cloud Hosted Run SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_HOSTED }} MSG_MINIMAL: Ref,Event,Commit - SLACK_FOOTER: 'Appsmith CI runs' - - # Upload the log artifact so that it can be used by the test & deploy job in the workflow - - name: Upload server logs bundle on failure - uses: actions/upload-artifact@v3 - if: failure() - with: - name: server-logs-${{ matrix.job }} - path: app/server/server-logs.log + SLACK_FOOTER: "Hosted run" # Set status = success - name: Save the status of the run diff --git a/.github/workflows/ci-test-limited.yml b/.github/workflows/ci-test-limited.yml index 8b310b81ce..660c29226e 100644 --- a/.github/workflows/ci-test-limited.yml +++ b/.github/workflows/ci-test-limited.yml @@ -3,6 +3,22 @@ name: Appsmith CI run limited Tests Workflow on: # This line enables manual triggering of this workflow. workflow_dispatch: + inputs: + pr: + description: "PR number" + required: false + type: number + default: 0 + previous-workflow-run-id: + description: "Workflow ID (To Download cicontainer)" + required: false + type: number + default: 0 + matrix: + description: "Matrix jobs" + required: false + type: string + default: "[0, 1, 2]" workflow_call: inputs: pr: @@ -55,6 +71,12 @@ jobs: - name: Set up Depot CLI uses: depot/setup-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + # Check out merge commit - name: Fork based /ok-to-test checkout if: inputs.pr != 0 @@ -89,46 +111,28 @@ jobs: id: run_result run: | run_result_env=$(cat ~/run_result) - echo "::set-output name=run_result::$run_result_env" - - # In case this is second attempt try restoring failed tests - - name: Restore the previous failed combine result - if: steps.run_result.outputs.run_result == 'failedtest' - uses: actions/download-artifact@v3 - with: - name: combined_failed_spec_ci - path: ~/combined_failed_spec_ci - - # failed_spec_env will contain list of all failed specs - # We are using environment variable instead of regular to support multiline - - name: Get failed_spec - id: failed_spec - if: steps.run_result.outputs.run_result == 'failedtest' - working-directory: app/client - run: | - echo "failed_spec_env<> $GITHUB_ENV - while IFS= read -r line - do - spec_name=$(echo $line | awk -F'/' '{print $NF}') - failed_spec_env=$(find . -name $spec_name | sed 's|./||') - echo "$failed_spec_env" >> $GITHUB_ENV - done < ~/combined_failed_spec_ci/combined_failed_spec_ci - echo "EOF" >> $GITHUB_ENV + echo "run_result=$run_result_env" >> $GITHUB_OUTPUT + if [[ "$run_result_env" == "failedtest" ]]; then + echo "rerun=true" >> $GITHUB_OUTPUT + else + echo "rerun=false" >> $GITHUB_OUTPUT + fi # Get specs to run - name: Get specs to run - if: steps.run_result.outputs.run_result != 'success' + if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' run: | - echo "specs_to_run<> $GITHUB_ENV + specs_to_run="" while IFS= read -r line do if [[ $line =~ ^#|^\/\/ ]]; then continue else - echo "$line" >> $GITHUB_ENV + specs_to_run="$specs_to_run,$line" fi done < app/client/cypress/limited-tests.txt - echo "EOF" >> $GITHUB_ENV + specs_to_run=${specs_to_run#,} + echo "specs_to_run=$specs_to_run" >> $GITHUB_ENV # In case of run-id provided download the artifact from the previous run - name: Download Docker image artifact @@ -166,6 +170,36 @@ jobs: docker run --name test-event-driver -d -p 22:22 -p 5001:5001 -p 3306:3306 \ -p 5432:5432 -p 28017:27017 -p 25:25 -p 5000:5000 -p 3001:3000 -p 6001:6001 --privileged --pid=host --ipc=host --volume /:/host -v ~/git-server/keys:/git-server/keys \ -v ~/git-server/repos:/git-server/repos appsmith/test-event-driver:latest + docker run --name cloud-services -d -p 8000:80 -p 8090:8090 \ + --privileged --pid=host --ipc=host --add-host=host.docker.internal:host-gateway\ + -e APPSMITH_CLOUD_SERVICES_MONGODB_URI=mongodb://host.docker.internal:27017 \ + -e APPSMITH_CLOUD_SERVICES_MONGODB_DATABASE=cs \ + -e APPSMITH_CLOUD_SERVICES_MONGODB_AUTH_DATABASE=admin \ + -e APPSMITH_REDIS_URL=redis://host.docker.internal:6379/ \ + -e APPSMITH_APPS_API_KEY=dummy-api-key \ + -e APPSMITH_REMOTE_API_KEY=dummy-api-key \ + -e APPSMITH_GITHUB_API_KEY=dummy-appsmith-gh-api-key \ + -e APPSMITH_JWT_SECRET=appsmith-cloud-services-jwt-secret-dummy-key \ + -e APPSMITH_ENCRYPTION_SALT=encryption-salt \ + -e APPSMITH_ENCRYPTION_PASSWORD=encryption-password \ + -e APPSMITH_CLOUD_SERVICES_URL=https://cs-dev.appsmith.com \ + -e APPSMITH_CUSTOMER_PORTAL_URL=https://dev.appsmith.com \ + -e APPSMITH_CLOUD_SERVICES_BASE_URL=https://cs-dev.appsmith.com \ + -e APPSMITH_CLOUD_SERVER_BASE_URL=https://release.app.appsmith.com \ + -e AUTH0_ISSUER_URL=https://login.release-customer.appsmith.com/ \ + -e AUTH0_CLIENT_ID=dummy-client-id \ + -e AUTH0_CLIENT_SECRET=dummy-secret-id \ + -e AUTH0_AUDIENCE_URL=https://login.local-customer.appsmith.com/ \ + -e CLOUDSERVICES_URL=cs-dev.appsmith.com \ + -e CUSTOMER_URL=dev.appsmith.com \ + -e ENTERPRISE_USER_NAME=ent-user@appsmith.com \ + -e ENTERPRISE_USER_PASSWORD=ent_user_password \ + -e ENTERPRISE_ADMIN_NAME=ent-admin@appsmith.com \ + -e ENTERPRISE_ADMIN_PASSWORD=ent_admin_password \ + -e FLAGSMITH_URL=http://host.docker.internal:5001/flagsmith \ + -e FLAGSMITH_SERVER_KEY=dummykey \ + -e FLAGSMITH_SERVER_KEY_BUSINESS_FEATURES=dummykeybusinessfeatures \ + appsmith/cloud-services:release cd cicontainerlocal docker run -d --name appsmith -p 80:80 -p 9001:9001 \ -v "$PWD/stacks:/appsmith-stacks" \ @@ -201,50 +235,6 @@ jobs: - name: Setting up the cypress tests if: steps.run_result.outputs.run_result != 'success' shell: bash - env: - APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} - APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} - CYPRESS_URL: ${{ secrets.CYPRESS_URL }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - POSTGRES_PASSWORD: postgres - CYPRESS_VERIFY_TIMEOUT: 100000 run: | cd app/client chmod a+x ./cypress/setup-test-ci.sh @@ -256,12 +246,6 @@ jobs: - run: | echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV - # - name: Set Pull Request Title - # env: - # EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }} - # run: | - # echo "test: Cypress (#24586)\n\n## Description\r\n- This PR adds the No Error toast to NavigateBacktoEditor() which\r\nsometimes results in Edit page not being load in CI runs" | awk -F '\\\\n' '{sub(/.*#/, "#", $1); sub(/).*/, "", $1); print $1}' - - name: Save Git values # pass env variables from this step to other steps # using GitHub Actions environment file @@ -296,17 +280,17 @@ jobs: elif [[ ${{ inputs.pr }} -ne 0 && ${{github.event_name}} == 'workflow_dispatch' ]]; then echo "COMMIT_INFO_MESSAGE=Workflow run on PR# ${{ inputs.pr }}" >> $GITHUB_ENV else - echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV + if [[ '${{env.EVENT_COMMITS}}' == 'null' ]]; then + echo "COMMIT_INFO_MESSAGE=${{ github.event_name }} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV + else + echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV + fi fi - name: Run the cypress test - id: cypress_test - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} @@ -321,6 +305,10 @@ jobs: CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} @@ -341,86 +329,56 @@ jobs: CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} CYPRESS_EXCLUDE_TAGS: "airgap" CYPRESS_AIRGAPPED: false APPSMITH_DISABLE_TELEMETRY: true APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} + POSTGRES_PASSWORD: postgres CYPRESS_VERIFY_TIMEOUT: 100000 + COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} + RUNID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + REPOSITORY: ${{ github.repository }} + COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }} + TAG: ${{ github.event_name }} + BRANCH: ${{ env.COMMIT_INFO_BRANCH }} + THIS_RUNNER: ${{ strategy.job-index }} + CYPRESS_SPECS: ${{ env.specs_to_run }} + CYPRESS_RERUN: ${{steps.run_result.outputs.rerun}} + CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }} + CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }} + CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }} with: browser: ${{ env.BROWSER_PATH }} - record: true install: false - parallel: true - config-file: cypress_ci.config.ts - group: "Chrome-Fat Container tests" + config-file: cypress_ci_custom.config.ts spec: ${{ env.specs_to_run }} working-directory: app/client - # tag will be either "push" or "pull_request" - tag: ${{ github.event_name }} env: "NODE_ENV=development" - # In case of second attempt only run failed specs - - name: Run the cypress test with failed tests - id: cypress_test_failedtest - if: steps.run_result.outputs.run_result == 'failedtest' - uses: cypress-io/github-action@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} - CYPRESS_VERIFY_TIMEOUT: 100000 + - name: Trim number of cypress log files + if: failure() + run: | + find ${{ github.workspace }}/app/client/cypress/cypress-logs -name '*.json' -type f | tail -n +11 | xargs -I {} rm -- {} + + - name: Upload failed test cypress logs artifact + if: failure() + uses: actions/upload-artifact@v3 with: - browser: ${{ env.BROWSER_PATH }} - record: true - install: false - parallel: true - config-file: cypress_ci.config.ts - group: "Chrome-Fat Container tests" - spec: ${{ env.failed_spec_env }} - working-directory: app/client - # tag will be either "push" or "pull_request" - tag: ${{ github.event_name }} - env: "NODE_ENV=development" + name: cypress-console-logs + path: ${{ github.workspace }}/app/client/cypress/cypress-logs + + - name: Upload cypress snapshots + if: always() + uses: actions/upload-artifact@v3 + with: + name: snapshots + path: ${{ github.workspace }}/app/client/cypress/snapshots - name: Collect CI container logs if: failure() @@ -437,35 +395,25 @@ jobs: name: dockerlogs path: ~/dockerlogs + - name: Rename reports + if: failure() + run: | + mkdir -p ~/results + mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }} + + - name: Upload cypress report + if: failure() + uses: actions/upload-artifact@v3 + with: + name: results-${{github.run_attempt}} + path: ~/results + # Set status = failedtest - name: Set fail if there are test failures if: failure() run: | - echo "::set-output name=run_result::failedtest" echo "failedtest" > ~/run_result - # Create a directory ~/failed_spec_ci and add a dummy file - # This will ensure upload and download steps are successful - - name: Create directory for failed tests - if: always() - run: | - mkdir -p ~/failed_spec_ci-${{github.run_attempt}} - - # add list failed tests to a file - - name: In case of test failures copy them to a file - if: failure() - run: | - cd ${{ github.workspace }}/app/client/cypress/ - find screenshots -type f \( -iname "*\(attempt 2\).png" -o -iname "*before all hook*" -o -iname "*after all hook*" \) | sed 's/screenshots/cypress\/e2e/g'| sed 's:/[^/]*$::' | sort -u > ~/failed_spec_ci-${{github.run_attempt}}/failed_spec_ci-${{ matrix.job }} - - # Upload failed test list using common path for all matrix job - - name: Upload failed test list artifact - if: failure() - uses: actions/upload-artifact@v3 - with: - name: failed-spec-ci-${{github.run_attempt}} - path: ~/failed_spec_ci-${{github.run_attempt}} - # Force store previous run result to cache - name: Store the previous run result if: failure() @@ -485,25 +433,6 @@ jobs: name: server-logs-${{ matrix.job }} path: app/server/server-logs.log - - name: get cypress url dashboard url - id: dashboard_url - if: always() - run: | - if [[ "${{steps.run_result.outputs.run_result }}" != "success" && "${{steps.run_result.outputs.run_result }}" != "failedtest" ]]; then - echo ${{ steps.cypress_test.outputs.resultsUrl }} >> ~/cypress_url - elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then - echo ${{ steps.cypress_test_failedtest.outputs.resultsUrl }} >> ~/cypress_url - fi - - # Force store previous run result to cache - - name: Store the previous run result - if: success() - uses: actions/cache/save@v3 - with: - path: | - ~/cypress_url - key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }} - # Set status = success - name: Save the status of the run run: | diff --git a/.github/workflows/ci-test-with-documentdb.yml b/.github/workflows/ci-test-with-documentdb.yml new file mode 100644 index 0000000000..58f18953f1 --- /dev/null +++ b/.github/workflows/ci-test-with-documentdb.yml @@ -0,0 +1,627 @@ +name: Appsmith CI Test (with DocumentDB) Workflow + +on: + # This line enables manual triggering of this workflow. + workflow_dispatch: + workflow_call: + inputs: + pr: + description: "This is the PR number in case the workflow is being called in a pull request" + required: false + type: number + +jobs: + ci-test: + runs-on: ubuntu-latest + if: | + github.event.pull_request.head.repo.full_name == github.repository || + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' || + github.event_name == 'repository_dispatch' + defaults: + run: + shell: bash + strategy: + fail-fast: false + matrix: + job: + [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + ] + + # Service containers to run with this job. Required for running tests + services: + # Label used to access the service container + redis: + # Docker Hub image for Redis + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + mongo: + image: mongo + ports: + - 27017:27017 + + steps: + - name: Set up Depot CLI + uses: depot/setup-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + # Check out merge commit + - name: Fork based /ok-to-test checkout + if: inputs.pr != 0 + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: "refs/pull/${{ inputs.pr }}/merge" + + # Checkout the code in the current branch in case the workflow is called because of a branch push event + - name: Checkout the head commit of the branch + if: inputs.pr == 0 + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + # Timestamp will be used to create cache key + - id: timestamp + run: echo "::set-output name=timestamp::$(date +'%Y-%m-%dT%H:%M:%S')" + + # In case this is second attempt try restoring status of the prior attempt from cache + - name: Restore the previous run result + id: cache-appsmith + uses: actions/cache@v3 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + - name: Get the previous run result + if: steps.cache-appsmith.outputs.cache-hit == 'true' + id: run_result + run: | + run_result_env=$(cat ~/run_result) + echo "run_result=$run_result_env" >> $GITHUB_OUTPUT + + - name: Dump steps context + env: + STEPS_CONTEXT: ${{ toJson(steps) }} + run: echo "$STEPS_CONTEXT" + + # In case this is second attempt try restoring failed tests + - if: steps.run_result.outputs.run_result == 'failedtest' + run: echo "failed_spec_artifact=failed-spec-ci-$((${{github.run_attempt}}-1))" >> $GITHUB_ENV + - name: Restore the previous failed combine result + if: steps.run_result.outputs.run_result == 'failedtest' + uses: actions/download-artifact@v3 + with: + name: ${{ env.failed_spec_artifact }} + path: ~/failed_spec_ci + + # failed_spec_env will contain list of all failed specs + # We are using environment variable instead of regular to support multiline + - name: Get failed_spec + id: failed_spec + if: steps.run_result.outputs.run_result == 'failedtest' + working-directory: app/client + run: | + failed_spec_env="" + while IFS= read -r line || [ -n "$line" ]; do + file_path=$(echo "$line" | awk -F'/' '{print $(NF-1)"/"$NF}') + spec_name=$(echo "$file_path" | awk -F'/' '{print $NF}') + failed_spec=$(find . -name "$spec_name" | sed 's|./||') + if [ "$(echo "$failed_spec" | wc -l)" -eq 1 ]; then + failed_spec_env="$failed_spec_env,$failed_spec" + else + for file in $failed_spec; do + new_file_path=$(echo "$file" | awk -F'/' '{print $(NF-1)"/"$NF}') + if [ "$new_file_path" == "$file_path" ]; then + failed_spec_env="$failed_spec_env,$file" + fi + done + fi + done < ~/failed_spec_ci/failed_spec_ci-${{ matrix.job }} + failed_spec_env=${failed_spec_env#,} + echo "failed_spec_env=$failed_spec_env" >> $GITHUB_ENV + + - if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' + run: echo "Starting full run" && exit 0 + + - if: steps.run_result.outputs.run_result == 'failedtest' + run: echo "Rerunning failed tests" && exit 0 + + - name: cat run_result + run: echo ${{ steps.run_result.outputs.run_result }} + + - name: Setup mongodb-tools + run: | + wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-ubuntu2204-x86_64-100.6.1.deb + sudo apt install ./mongodb-database-tools-*-100.6.1.deb + + - name: Download mongodb archive + run: | + curl -o data.gz https://appsmithctl-backup-restore-test.s3.ap-south-1.amazonaws.com/docdb-data.gz + + - name: Download Docker image artifact + uses: actions/download-artifact@v3 + with: + name: cicontainer + + - name: Load Docker image from tar file + run: | + gunzip cicontainer.tar.gz + docker load -i cicontainer.tar + + - name: Create folder + if: steps.run_result.outputs.run_result != 'success' + working-directory: "." + run: | + mkdir -p cicontainerlocal/stacks/configuration/ + + - name: Set up SSH key for tunnel + env: + SSH_PRIVATE_KEY: ${{ secrets.APPSMITH_CI_TUNNEL_PRIVATE_KEY }} + run: | + echo "$SSH_PRIVATE_KEY" > ssh_key.pem + chmod 400 ssh_key.pem + + - name: Setup SSH tunnel to AWS DocumentDB instance + run: | + chmod 400 ssh_key.pem + ssh -4 -o StrictHostKeyChecking=no -o ServerAliveInterval=180 -o ServerAliveCountMax=5 -i "ssh_key.pem" -L 0.0.0.0:27010:docdb-ansible-test-cluster.cluster-cz8diybf9wdj.ap-south-1.docdb.amazonaws.com:27017 ubuntu@65.1.106.35 -N -f + + - name: Run Appsmith, CS & TED docker image + if: steps.run_result.outputs.run_result != 'success' + working-directory: "." + env: + APPSMITH_MONGODB_URI: ${{ secrets.INTERNAL_CI_DOC_DB_URI }} + + run: | + timestamp=$(date +%Y%m%d%H%M%S) + hash=$(hostname) + random=$(shuf -i 1000-9999 -n 1) + DB_NAME="${timestamp}-${hash}-${random}" + echo "DB_NAME: ${DB_NAME}" + MONGO_CREDS=$(echo $APPSMITH_MONGODB_URI | sed 's/@.*//') + URI="${MONGO_CREDS}@localhost:27010/${DB_NAME}?retryWrites=false&replicaSet=rs0&directConnection=true" + mongorestore --uri="${URI}" --archive=data.gz --gzip --drop --nsInclude "doc-db-base.*" --nsFrom "doc-db-base.*" --nsTo "${DB_NAME}.*" + sudo /etc/init.d/ssh stop ; + mkdir -p ~/git-server/keys + mkdir -p ~/git-server/repos + docker run --name test-event-driver -d -p 22:22 -p 5001:5001 -p 3306:3306 \ + -p 5432:5432 -p 28017:27017 -p 25:25 -p 5000:5000 -p 3001:3000 -p 6001:6001 --privileged --pid=host --ipc=host --volume /:/host -v ~/git-server/keys:/git-server/keys \ + -v ~/git-server/repos:/git-server/repos appsmith/test-event-driver:latest + docker run --name cloud-services -d -p 8000:80 -p 8090:8090 \ + --privileged --pid=host --ipc=host --add-host=host.docker.internal:host-gateway\ + -e APPSMITH_CLOUD_SERVICES_MONGODB_URI=mongodb://host.docker.internal:27017 \ + -e APPSMITH_CLOUD_SERVICES_MONGODB_DATABASE=cs \ + -e APPSMITH_CLOUD_SERVICES_MONGODB_AUTH_DATABASE=admin \ + -e APPSMITH_REDIS_URL=redis://host.docker.internal:6379/ \ + -e APPSMITH_APPS_API_KEY=dummy-api-key \ + -e APPSMITH_REMOTE_API_KEY=dummy-api-key \ + -e APPSMITH_GITHUB_API_KEY=dummy-appsmith-gh-api-key \ + -e APPSMITH_JWT_SECRET=appsmith-cloud-services-jwt-secret-dummy-key \ + -e APPSMITH_ENCRYPTION_SALT=encryption-salt \ + -e APPSMITH_ENCRYPTION_PASSWORD=encryption-password \ + -e APPSMITH_CLOUD_SERVICES_URL=https://cs-dev.appsmith.com \ + -e APPSMITH_CUSTOMER_PORTAL_URL=https://dev.appsmith.com \ + -e APPSMITH_CLOUD_SERVICES_BASE_URL=https://cs-dev.appsmith.com \ + -e APPSMITH_CLOUD_SERVER_BASE_URL=https://release.app.appsmith.com \ + -e AUTH0_ISSUER_URL=https://login.release-customer.appsmith.com/ \ + -e AUTH0_CLIENT_ID=dummy-client-id \ + -e AUTH0_CLIENT_SECRET=dummy-secret-id \ + -e AUTH0_AUDIENCE_URL=https://login.local-customer.appsmith.com/ \ + -e CLOUDSERVICES_URL=cs-dev.appsmith.com \ + -e CUSTOMER_URL=dev.appsmith.com \ + -e ENTERPRISE_USER_NAME=ent-user@appsmith.com \ + -e ENTERPRISE_USER_PASSWORD=ent_user_password \ + -e ENTERPRISE_ADMIN_NAME=ent-admin@appsmith.com \ + -e ENTERPRISE_ADMIN_PASSWORD=ent_admin_password \ + appsmith/cloud-services:release + cd cicontainerlocal + docker run -d --name appsmith -p 80:80 -p 9001:9001 \ + -v "$PWD/stacks:/appsmith-stacks" \ + -e APPSMITH_DISABLE_TELEMETRY=true \ + -e APPSMITH_INTERCOM_APP_ID=DUMMY_VALUE \ + -e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \ + -e APPSMITH_MONGODB_URI="${APPSMITH_MONGODB_URI}${DB_NAME}?retryWrites=false&replicaSet=rs0&directConnection=true" \ + --add-host=host.docker.internal:host-gateway --add-host=api.segment.io:host-gateway --add-host=t.appsmith.com:host-gateway \ + cicontainer + + - name: Use Node.js + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-node@v3 + with: + node-version-file: app/client/package.json + + # actions/setup-node@v3 doesn’t work properly with Yarn 3 + # when the project lives in a subdirectory: https://github.com/actions/setup-node/issues/488 + # Restoring the cache manually instead + - name: Restore Yarn cache + if: steps.run_result.outputs.run_result != 'success' + uses: actions/cache@v3 + with: + path: app/client/.yarn/cache + key: v1-yarn3-${{ hashFiles('app/client/yarn.lock') }} + restore-keys: | + v1-yarn3- + + # Install all the dependencies + - name: Install dependencies + if: steps.run_result.outputs.run_result != 'success' + working-directory: app/client + run: | + yarn install --immutable + + - name: Wait until appsmith server is healthy + run: | + bash scripts/health_check.sh + + - name: Setting up the cypress tests + if: steps.run_result.outputs.run_result != 'success' + shell: bash + run: | + cd app/client + chmod a+x ./cypress/setup-test-ci.sh + ./cypress/setup-test-ci.sh + + - uses: browser-actions/setup-chrome@latest + with: + chrome-version: stable + - run: | + echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV + + - name: Save Git values + # pass env variables from this step to other steps + # using GitHub Actions environment file + # https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#environment-files + run: | + PR_NUMBER=${{ inputs.pr }} + echo COMMIT_INFO_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV + echo COMMIT_INFO_MESSAGE=OkToTest run on PR# ${{ inputs.pr }} >> $GITHUB_ENV + echo COMMIT_INFO_EMAIL=$(git show -s --pretty=%ae) >> $GITHUB_ENV + echo COMMIT_INFO_AUTHOR=$(git show -s --pretty=%an) >> $GITHUB_ENV + echo COMMIT_INFO_SHA=$(git show -s --pretty=%H) >> $GITHUB_ENV + echo COMMIT_INFO_TIMESTAMP=$(git show -s --pretty=%ct) >> $GITHUB_ENV + echo COMMIT_INFO_REMOTE=$(git config --get remote.origin.url) >> $GITHUB_ENV + # delete the .git folder afterwords to use the environment values + rm -rf .git + + - name: Show Git values + run: | + echo Branch $COMMIT_INFO_BRANCH + echo Message $COMMIT_INFO_MESSAGE + echo Email $COMMIT_INFO_EMAIL + echo Author $COMMIT_INFO_AUTHOR + echo SHA $COMMIT_INFO_SHA + echo Timestamp $COMMIT_INFO_TIMESTAMP + echo Remote $COMMIT_INFO_REMOTE + + - name: Set Commit Message + env: + EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }} + run: | + if [[ ${{ inputs.pr }} -ne 0 ]]; then + echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE }}" >> $GITHUB_ENV + else + if [[ '${{env.EVENT_COMMITS}}' == 'null' ]]; then + echo "COMMIT_INFO_MESSAGE=${{ github.event_name }} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV + else + echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV + fi + fi + + - name: Run the cypress test + if: steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' + id: cypress_test + uses: cypress-io/github-action@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} + CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} + CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} + CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} + CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} + CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} + CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} + CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} + CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} + CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} + CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} + CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} + CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} + CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} + CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} + CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} + CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} + CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} + CYPRESS_EXCLUDE_TAGS: "airgap" + CYPRESS_AIRGAPPED: false + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} + CYPRESS_VERIFY_TIMEOUT: 100000 + TOTAL_RUNNERS: ${{ strategy.job-total }} + THIS_RUNNER: ${{ strategy.job-index }} + CYPRESS_SPEC_PATTERN: "cypress/e2e/**/**/*" + CYPRESS_ENV: "NODE_ENV=development" + CYPRESS_CONFIG_FILE: cypress_ci_custom.config.ts + CYPRESS_HEADLESS: "true" + CYPRESS_BROWSER: ${{ env.BROWSER_PATH }} + RUNID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + REPOSITORY: ${{ github.repository }} + COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }} + TAG: ${{ github.event_name }} + BRANCH: ${{ env.COMMIT_INFO_BRANCH }} + CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }} + CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }} + CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }} + with: + install: false + working-directory: app/client + command: yarn ts-node --require esm cypress/cypress-split.ts + + # In case of second attempt only run failed specs + - name: Run the cypress test with failed tests + if: steps.run_result.outputs.run_result == 'failedtest' + id: cypress_test_failedtest + uses: cypress-io/github-action@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} + CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} + CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} + CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} + CYPRESS_ORACLE_HOST: ${{ secrets.ORACLE_HOST }} + CYPRESS_ORACLE_SERVICE: ${{ secrets.ORACLE_SERVICE }} + CYPRESS_ORACLE_USERNAME: ${{ secrets.ORACLE_USERNAME }} + CYPRESS_ORACLE_PASSWORD: ${{ secrets.ORACLE_PASSWORD }} + CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} + CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} + CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} + CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} + CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} + CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} + CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} + CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} + CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} + CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} + CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} + CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} + CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} + CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} + CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_OKTA_PASSWORD }} + CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_DIRECT_URL }} + CYPRESS_EXCLUDE_TAGS: "airgap" + CYPRESS_AIRGAPPED: false + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} + CYPRESS_ENV: "NODE_ENV=development" + CYPRESS_CONFIG_FILE: cypress_ci.config.ts + CYPRESS_HEADLESS: "true" + CYPRESS_BROWSER: ${{ env.BROWSER_PATH }} + RUNID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + REPOSITORY: ${{ github.repository }} + COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }} + TAG: ${{ github.event_name }} + BRANCH: ${{ env.COMMIT_INFO_BRANCH }} + THIS_RUNNER: ${{ strategy.job-index }} + CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }} + CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }} + CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }} + with: + install: false + working-directory: app/client + command: yarn cypress run --browser ${{ env.BROWSER_PATH }} --config-file cypress_ci_custom.config.ts --spec ${{ env.failed_spec_env }} + + - name: Collect CI container logs + if: failure() + working-directory: "." + run: | + mkdir -p ~/dockerlogs + docker logs appsmith 2>&1 > ~/dockerlogs/dockerlogs-${{ matrix.job }}.txt + + # Upload docker logs + - name: Upload failed test list artifact + if: failure() + uses: actions/upload-artifact@v3 + with: + name: dockerlogs + path: ~/dockerlogs + + - name: Rename reports + if: always() + run: | + mkdir -p ~/results + mv ${{ github.workspace }}/app/client/results ~/results/${{ matrix.job }} + + - name: Upload cypress report + if: always() + uses: actions/upload-artifact@v3 + with: + name: results-${{github.run_attempt}} + path: ~/results + + # Set status = failedtest + - name: Set fail if there are test failures + if: failure() + run: | + echo "run_result=failedtest" >> $GITHUB_OUTPUT + echo "failedtest" > ~/run_result + + # Create a directory ~/failed_spec_ci and add a dummy file + # This will ensure upload and download steps are successful + - name: Create directory for failed tests + if: always() + run: | + mkdir -p ~/failed_spec_ci-${{github.run_attempt}} + + # add list failed tests to a file + - name: In case of test failures copy them to a file + if: failure() + run: | + cd ${{ github.workspace }}/app/client/cypress/ + find screenshots -type f \( -iname "*\(attempt 2\).png" -o -iname "*before all hook*" -o -iname "*after all hook*" \) | sed 's/screenshots/cypress\/e2e/g'| sed 's:/[^/]*$::' | sort -u > ~/failed_spec_ci-${{github.run_attempt}}/failed_spec_ci-${{ matrix.job }} + + # Upload failed test list using common path for all matrix job + - name: Upload failed test list artifact + if: failure() + uses: actions/upload-artifact@v3 + with: + name: failed-spec-ci-${{github.run_attempt}} + path: ~/failed_spec_ci-${{github.run_attempt}} + + # Force store previous run result to cache + - name: Store the previous run result + if: failure() + uses: actions/cache/save@v3 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} + + # - name: get cypress url dashboard url + # id: dashboard_url + # if: always() + # run: | + # if [[ "${{steps.run_result.outputs.run_result }}" != "success" && "${{steps.run_result.outputs.run_result }}" != "failedtest" ]]; then + # echo "" >> ~/cypress_url + # elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then + # echo "" >> ~/cypress_url + # fi + + # Force store previous run result to cache + - name: Store the previous run result + if: success() + uses: actions/cache/save@v3 + with: + path: | + ~/cypress_url + key: ${{ github.run_id }}-dashboard-url-${{ github.run_number }} + + # Upload the log artifact so that it can be used by the test & deploy job in the workflow + - name: Upload server logs bundle on failure + uses: actions/upload-artifact@v3 + if: failure() + with: + name: server-logs-${{ matrix.job }} + path: app/server/server-logs.log + + # Set status = success + - name: Save the status of the run + run: | + echo "run_result=success" >> $GITHUB_OUTPUT + echo "success" > ~/run_result diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml index e80f718286..9129b1ba55 100644 --- a/.github/workflows/ci-test.yml +++ b/.github/workflows/ci-test.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - job: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59] + job: [0] # Service containers to run with this job. Required for running tests services: @@ -178,6 +178,9 @@ jobs: -e ENTERPRISE_USER_PASSWORD=ent_user_password \ -e ENTERPRISE_ADMIN_NAME=ent-admin@appsmith.com \ -e ENTERPRISE_ADMIN_PASSWORD=ent_admin_password \ + -e FLAGSMITH_URL=http://host.docker.internal:5001/flagsmith \ + -e FLAGSMITH_SERVER_KEY=dummykey \ + -e FLAGSMITH_SERVER_KEY_BUSINESS_FEATURES=dummykeybusinessfeatures \ appsmith/cloud-services:release cd cicontainerlocal docker run -d --name appsmith -p 80:80 -p 9001:9001 \ @@ -217,50 +220,6 @@ jobs: - name: Setting up the cypress tests if: steps.run_result.outputs.run_result != 'success' shell: bash - env: - APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} - APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} - CYPRESS_URL: ${{ secrets.CYPRESS_URL }} - CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} - CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} - CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} - CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} - CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} - CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} - CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} - CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} - CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} - CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} - CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} - CYPRESS_GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - CYPRESS_AIRTABLE_BEARER: ${{ secrets.AIRTABLE_BEARER }} - CYPRESS_FIRESTORE_PRIVATE_KEY: ${{ secrets.FIRESTORE_PRIVATE_KEY }} - CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.CYPRESS_GITHUB_PERSONAL_ACCESS_TOKEN }} - CYPRESS_TEST_GITHUB_USER_NAME: ${{ secrets.CYPRESS_TEST_GITHUB_USER_NAME }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} - CYPRESS_OAUTH_SAML_EMAIL: ${{ secrets.CYPRESS_OAUTH_SAML_EMAIL }} - CYPRESS_OAUTH_SAML_ENTITY_ID: ${{ secrets.CYPRESS_OAUTH_SAML_ENTITY_ID }} - CYPRESS_OAUTH_SAML_METADATA_URL: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_URL }} - CYPRESS_OAUTH_SAML_METADATA_XML: ${{ secrets.CYPRESS_OAUTH_SAML_METADATA_XML }} - CYPRESS_OAUTH_SAML_PUB_CERT: ${{ secrets.CYPRESS_OAUTH_SAML_PUB_CERT }} - CYPRESS_OAUTH_SAML_SSO_URL: ${{ secrets.CYPRESS_OAUTH_SAML_SSO_URL }} - CYPRESS_OAUTH_SAML_REDIRECT_URL: ${{ secrets.CYPRESS_OAUTH_SAML_REDIRECT_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_ID }} - CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_CLIENT_SECRET }} - CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_AUTH_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_TOKEN_URL }} - CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_USER_INFO }} - CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_OIDC_JWKS_URL }} - CYPRESS_EXCLUDE_TAGS: "airgap" - CYPRESS_AIRGAPPED: false - APPSMITH_DISABLE_TELEMETRY: true - APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} - POSTGRES_PASSWORD: postgres - CYPRESS_VERIFY_TIMEOUT: 100000 run: | cd app/client chmod a+x ./cypress/setup-test-ci.sh @@ -311,7 +270,11 @@ jobs: if [[ ${{ inputs.pr }} -ne 0 ]]; then echo "COMMIT_INFO_MESSAGE=${{ env.COMMIT_INFO_MESSAGE }}" >> $GITHUB_ENV else - echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV + if [[ '${{env.EVENT_COMMITS}}' == 'null' ]]; then + echo "COMMIT_INFO_MESSAGE=${{ github.event_name }} by ${{ env.COMMIT_INFO_AUTHOR }}" >> $GITHUB_ENV + else + echo "COMMIT_INFO_MESSAGE=$(echo \"${{ env.EVENT_COMMITS }}\" | awk -F '\\\\n' '{print $1}' | sed 's/^\"//')" >> $GITHUB_ENV + fi fi - name: Run the cypress test @@ -362,6 +325,19 @@ jobs: APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} CYPRESS_VERIFY_TIMEOUT: 100000 + RUNID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + REPOSITORY: ${{ github.repository }} + COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }} + TAG: ${{ github.event_name }} + BRANCH: ${{ env.COMMIT_INFO_BRANCH }} + THIS_RUNNER: ${{ strategy.job-index }} + CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }} + CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }} + CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }} with: browser: ${{ env.BROWSER_PATH }} record: true @@ -441,6 +417,19 @@ jobs: APPSMITH_DISABLE_TELEMETRY: true APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} COMMIT_INFO_MESSAGE: ${{ env.COMMIT_INFO_MESSAGE }} + RUNID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + REPOSITORY: ${{ github.repository }} + COMMITTER: ${{ env.COMMIT_INFO_AUTHOR }} + TAG: ${{ github.event_name }} + BRANCH: ${{ env.COMMIT_INFO_BRANCH }} + THIS_RUNNER: ${{ strategy.job-index }} + CYPRESS_DB_USER: ${{ secrets.CYPRESS_DB_USER }} + CYPRESS_DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + CYPRESS_DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + CYPRESS_DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + CYPRESS_S3_ACCESS: ${{ secrets.CYPRESS_S3_ACCESS }} + CYPRESS_S3_SECRET: ${{ secrets.CYPRESS_S3_SECRET }} with: browser: ${{ env.BROWSER_PATH }} record: true @@ -507,15 +496,15 @@ jobs: ~/run_result key: ${{ github.run_id }}-${{ github.job }}-${{ matrix.job }} - - name: get cypress url dashboard url - id: dashboard_url - if: always() - run: | - if [[ "${{steps.run_result.outputs.run_result }}" != "success" && "${{steps.run_result.outputs.run_result }}" != "failedtest" ]]; then - echo ${{ steps.cypress_test.outputs.resultsUrl }} >> ~/cypress_url - elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then - echo ${{ steps.cypress_test_failedtest.outputs.resultsUrl }} >> ~/cypress_url - fi + # - name: get cypress url dashboard url + # id: dashboard_url + # if: always() + # run: | + # if [[ "${{steps.run_result.outputs.run_result }}" != "success" && "${{steps.run_result.outputs.run_result }}" != "failedtest" ]]; then + # echo ${{ steps.cypress_test.outputs.resultsUrl }} >> ~/cypress_url + # elif [[ "${{steps.run_result.outputs.run_result }}" == "failedtest" ]]; then + # echo ${{ steps.cypress_test_failedtest.outputs.resultsUrl }} >> ~/cypress_url + # fi # Force store previous run result to cache - name: Store the previous run result diff --git a/.github/workflows/cleanup-dp.yml b/.github/workflows/cleanup-dp.yml index e105c83789..6f4c4781e3 100644 --- a/.github/workflows/cleanup-dp.yml +++ b/.github/workflows/cleanup-dp.yml @@ -1,6 +1,7 @@ name: Cleanup Deploy Previews on: + workflow_dispatch: schedule: - cron: 0 0 * * * diff --git a/.github/workflows/client-build.yml b/.github/workflows/client-build.yml index 8c70e57efa..01d797189b 100644 --- a/.github/workflows/client-build.yml +++ b/.github/workflows/client-build.yml @@ -21,7 +21,11 @@ on: description: "This is the branch to be used for the build." required: false type: string - + ads-compliant-check: + description: "This is a boolean value in case the workflow is being called in build deploy-preview" + required: false + type: string + default: "true" # Change the working directory for all the jobs in this workflow defaults: @@ -76,7 +80,7 @@ jobs: uses: umani/changed-files@v4.0.0 with: repo-token: ${{ secrets.APPSMITH_CI_TEST_PAT }} - pattern: 'app/client/cypress/e2e/.*' + pattern: "app/client/cypress/e2e/.*" pr-number: ${{ inputs.pr }} # Check all the newly added files are in ts @@ -107,6 +111,46 @@ jobs: - if: steps.check_files.outputs.non_ts_files_count != 0 && inputs.check-test-files == 'true' && inputs.pr != 0 run: exit 1 + - name: Get all the added or changed files in client/src folder + if: inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release' + id: client_files + uses: umani/changed-files@v4.0.0 + with: + repo-token: ${{ secrets.APPSMITH_CI_TEST_PAT }} + pattern: "app/client/src/.*" + pr-number: ${{ inputs.pr }} + + # Check all the newly added files are in ts + - name: ADS compliant check + if: inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release' + id: ads_check + run: | + comment_files="" + files=(${{steps.client_files.outputs.files_created}}${{steps.client_files.outputs.files_updated}}) + for file in "${files[@]}"; do + while IFS= read -r line; do + if echo "$line" | grep -q -E '(color|Color).*#|border.*#|(color|Color).*"'; then + comment_files+=("$file") + break + fi + done < ${file#app/client/} + done + unique_files=$(echo "${comment_files[@]}" | sort -u | sed '/^[[:space:]]*$/d' | sed 's/ /
  • /g') + echo "ads_non_compliant_files=$unique_files" >> $GITHUB_OUTPUT + echo "ads_non_compliant_count=${#unique_files[@]}" >> $GITHUB_OUTPUT + + # Comment in PR if test files are not written in ts and fail the workflow + - name: Comment in PR if test files are not written in ts + if: steps.ads_check.outputs.ads_non_compliant_count != 0 && inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release' + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ inputs.pr }} + body: | + 🔴 Below files are not compliant with ADS. Please fix and re-trigger ok-to-test +
      ${{steps.ads_check.outputs.ads_non_compliant_files}}
    + - if: steps.ads_check.outputs.ads_non_compliant_count != 0 && inputs.ads-compliant-check == 'true' && inputs.pr != 0 && github.pull_request.base.ref == 'release' + run: exit 1 + # Create a run record exactly at the time of merge to release to # ensure we compare run details with code at this point - name: Create Perf Meta diff --git a/.github/workflows/docker-base-image.yml b/.github/workflows/docker-base-image.yml new file mode 100644 index 0000000000..f63811839a --- /dev/null +++ b/.github/workflows/docker-base-image.yml @@ -0,0 +1,57 @@ +name: Docker Base Image + +on: + workflow_dispatch: + schedule: + - cron: "0 5 * * MON" + push: + branches: + - release + - master + paths: + - "deploy/docker/base.dockerfile" + +jobs: + build-docker: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + + steps: + - name: Checkout the head commit of the branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Get tag + id: tag + run: | + tag="${GITHUB_REF_NAME//\//-}" + if [[ "$tag" == master ]]; then + tag=nightly + fi + echo "tag=$tag" >> "$GITHUB_OUTPUT" + + - name: Build and push base image + uses: docker/build-push-action@v5 + with: + context: . + file: deploy/docker/base.dockerfile + push: true + platforms: linux/arm64,linux/amd64 + tags: | + ${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:${{ steps.tag.outputs.tag }} diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index f2a3d23ae8..e28e32b5eb 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -269,6 +269,12 @@ jobs: echo "Cleaning up the tar files" rm app/client/packages/rts/dist/rts-dist.tar + - name: Generate info.json + run: | + if [[ -f scripts/generate_info_json.sh ]]; then + scripts/generate_info_json.sh + fi + - name: Login to DockerHub uses: docker/login-action@v1 with: @@ -283,6 +289,7 @@ jobs: platforms: linux/arm64,linux/amd64 build-args: | APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }} + BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:nightly tags: | ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:${{needs.prelude.outputs.tag}} @@ -296,5 +303,6 @@ jobs: platforms: linux/arm64,linux/amd64 build-args: | APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }} + BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:nightly tags: | ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:latest diff --git a/.github/workflows/integration-tests-command.yml b/.github/workflows/integration-tests-command.yml index 6758f86e98..0309f58782 100644 --- a/.github/workflows/integration-tests-command.yml +++ b/.github/workflows/integration-tests-command.yml @@ -3,7 +3,7 @@ name: Appsmith External Integration Test Workflow on: # This workflow is only triggered by the ok to test command dispatch repository_dispatch: - types: [ ok-to-test-command ] + types: [ok-to-test-command] jobs: notify: @@ -19,8 +19,7 @@ jobs: Workflow: `${{ github.workflow }}`. Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`. PR: ${{ github.event.client_payload.pull_request.number }}. - Perf tests will be available at - + server-build: name: server-build uses: ./.github/workflows/server-build.yml @@ -52,7 +51,7 @@ jobs: pr: ${{ github.event.client_payload.pull_request.number }} build-docker-image: - needs: [ client-build, server-build, rts-build ] + needs: [client-build, server-build, rts-build] # Only run if the build step is successful if: success() name: build-docker-image @@ -62,27 +61,17 @@ jobs: pr: ${{ github.event.client_payload.pull_request.number }} ci-test: - needs: [ build-docker-image ] + needs: [build-docker-image] # Only run if the build step is successful if: success() name: ci-test - uses: ./.github/workflows/ci-test.yml - secrets: inherit - with: - pr: ${{ github.event.client_payload.pull_request.number }} - - perf-test: - needs: [ build-docker-image ] - # Only run if the build step is successful - if: success() - name: perf-test - uses: ./.github/workflows/perf-test.yml + uses: ./.github/workflows/ci-test-custom-script.yml secrets: inherit with: pr: ${{ github.event.client_payload.pull_request.number }} ci-test-result: - needs: [ci-test, perf-test ] + needs: [ci-test] # Only run if the ci-test with matrices step is successful if: always() runs-on: ubuntu-latest @@ -95,54 +84,69 @@ jobs: PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} run: echo "$PAYLOAD_CONTEXT" - # Deleting the existing dir's if any - - name: Delete existing directories + - name: Setup node if: needs.ci-test.result != 'success' - run: | - rm -f ~/failed_spec_ci - rm -f ~/combined_failed_spec_ci - - # Force store previous cypress dashboard url from cache - - name: Store the previous cypress dashboard url - continue-on-error: true - if: success() - uses: actions/cache@v3 + uses: actions/setup-node@v3 with: - path: | - ~/cypress_url - key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }} - restore-keys: | - ${{ github.run_id }}-dashboard-url + node-version: 18 - - name: Print cypress dashboard url - continue-on-error: true - id: dashboard_url - run: | - cypress_url=$(cat ~/cypress_url) - echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT - - # Download failed_spec list for all jobs - - uses: actions/download-artifact@v3 + - name: install pg if: needs.ci-test.result != 'success' - id: download_ci + run: npm install pg + + - name: Fetch the failed specs + if: needs.ci-test.result != 'success' + id: failed_specs + env: + DB_HOST: ${{ secrets.CYPRESS_DB_HOST }} + DB_NAME: ${{ secrets.CYPRESS_DB_NAME }} + DB_USER: ${{ secrets.CYPRESS_DB_USER }} + DB_PWD: ${{ secrets.CYPRESS_DB_PWD }} + RUN_ID: ${{ github.run_id }} + ATTEMPT_NUMBER: ${{ github.run_attempt }} + uses: actions/github-script@v6 with: - name: failed-spec-ci-${{github.run_attempt}} - path: ~/failed_spec_ci - + script: | + const { Pool } = require("pg"); + const { DB_HOST, DB_NAME, DB_USER, DB_PWD, RUN_ID, ATTEMPT_NUMBER } = process.env + + const client = await new Pool({ + user: DB_USER, + host: DB_HOST, + database: DB_NAME, + password: DB_PWD, + port: 5432, + connectionTimeoutMillis: 60000, + }).connect(); + + const result = await client.query( + `SELECT DISTINCT name FROM public."specs" + WHERE "matrixId" IN + (SELECT id FROM public."matrix" + WHERE "attemptId" = ( + SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2 + ) + ) AND status = 'fail'`, + [RUN_ID, ATTEMPT_NUMBER], + ); + client.release(); + return result.rows.map((spec) => spec.name); + # In case for any ci job failure, create combined failed spec - name: combine all specs for CI id: combine_ci if: needs.ci-test.result != 'success' run: | - echo "Debugging: failed specs in ~/failed_spec_ci/failed_spec_ci*" - cat ~/failed_spec_ci/failed_spec_ci* - cat ~/failed_spec_ci/failed_spec_ci* | sort -u >> ~/combined_failed_spec_ci + failed_specs=$(echo ${{steps.failed_specs.outputs.result}} | sed 's/\[\|\]//g' | tr -d ' ' | tr ',' '\n') + while read -r line; do + echo "$line" >> ~/combined_failed_spec_ci + done <<< "$failed_specs" if [[ -z $(grep '[^[:space:]]' ~/combined_failed_spec_ci) ]] ; then echo "specs_failed=0" >> $GITHUB_OUTPUT else echo "specs_failed=1" >> $GITHUB_OUTPUT fi - + # Upload combined failed CI spec list to a file # This is done for debugging. - name: upload combined failed spec @@ -157,7 +161,7 @@ jobs: run: | curl --request POST --url https://yatin-s-workspace-jk8ru5.us-east-1.xata.sh/db/CypressKnownFailures:main/tables/CypressKnownFailuires/query --header 'Authorization: Bearer ${{ secrets.XATA_TOKEN }}' --header 'Content-Type: application/json'|jq -r |grep Spec|cut -d ':' -f 2 2> /dev/null|sed 's/"//g'|sed 's/,//g' > ~/knownfailures - # Verify CI test failures against known failures + # Verify CI test failures against known failures - name: Verify CI test failures against known failures if: needs.ci-test.result != 'success' shell: bash @@ -176,19 +180,30 @@ jobs: body: | Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`. - Cypress dashboard: Click here! + Cypress dashboard: Click here! The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}} - To know the list of identified flaky tests - Refer here + To know the list of identified flaky tests - Refer here - - name: Add a comment on the PR when ci-test is success - if: needs.ci-test.result == 'success' || steps.combine_ci.outputs.specs_failed == '0' + - name: Add a comment on the PR when ci-test is failed but no specs found + if: needs.ci-test.result != 'success' && steps.combine_ci.outputs.specs_failed == '0' uses: peter-evans/create-or-update-comment@v1 with: issue-number: ${{ github.event.client_payload.pull_request.number }} body: | Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`. - Cypress dashboard url: Click here! + Cypress dashboard url: Click here! + It seems like there are some failures 😔. We are not able to recognize it, please check this manually here. + + - name: Add a comment on the PR when ci-test is success + if: needs.ci-test.result == 'success' && steps.combine_ci.outputs.specs_failed == '0' + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ github.event.client_payload.pull_request.number }} + body: | + Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. + Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`. + Cypress dashboard url: Click here! All cypress tests have passed 🎉🎉🎉 # Update check run called "ci-test-result" @@ -261,11 +276,11 @@ jobs: run: echo "$PAYLOAD_CONTEXT" - name: Check ci-test set status - if: needs.ci-test.result != 'success' || needs.perf-test.result != 'success' + if: needs.ci-test.result != 'success' run: exit 1 package: - needs: [ ci-test ] + needs: [ci-test] runs-on: ubuntu-latest defaults: run: diff --git a/.github/workflows/integration-tests-with-documentdb-command.yml b/.github/workflows/integration-tests-with-documentdb-command.yml new file mode 100644 index 0000000000..f2edea48a0 --- /dev/null +++ b/.github/workflows/integration-tests-with-documentdb-command.yml @@ -0,0 +1,323 @@ +name: Appsmith External Integration Test (with DocumentDB ) Workflow + +on: + # This workflow is only triggered by the ok to test command dispatch + repository_dispatch: + types: [ok-to-test-with-documentdb-command] + +jobs: + notify: + runs-on: ubuntu-latest + steps: + # This step creates a comment on the PR with a link to this workflow run. + - name: Add a comment on the PR with link to workflow run + uses: peter-evans/create-or-update-comment@v2 + with: + issue-number: ${{ github.event.client_payload.pull_request.number }} + body: | + Tests running at: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. + Workflow: `${{ github.workflow }}`. + Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`. + PR: ${{ github.event.client_payload.pull_request.number }}. + + server-build: + name: server-build + uses: ./.github/workflows/server-build.yml + secrets: inherit + with: + pr: ${{ github.event.client_payload.pull_request.number }} + skip-tests: true + + client-build: + name: client-build + uses: ./.github/workflows/client-build.yml + secrets: inherit + with: + pr: ${{ github.event.client_payload.pull_request.number }} + check-test-files: "true" + + rts-build: + name: rts-build + uses: ./.github/workflows/rts-build.yml + secrets: inherit + with: + pr: ${{ github.event.client_payload.pull_request.number }} + + test-appsmithctl: + name: appsmithctl + uses: ./.github/workflows/appsmithctl.yml + secrets: inherit + with: + pr: ${{ github.event.client_payload.pull_request.number }} + + build-docker-image: + needs: [client-build, server-build, rts-build] + # Only run if the build step is successful + if: success() + name: build-docker-image + uses: ./.github/workflows/build-docker-image.yml + secrets: inherit + with: + pr: ${{ github.event.client_payload.pull_request.number }} + + ci-test: + needs: [build-docker-image] + # Only run if the build step is successful + if: success() + name: ci-test-with-documentDB + uses: ./.github/workflows/ci-test-with-documentdb.yml + secrets: inherit + with: + pr: ${{ github.event.client_payload.pull_request.number }} + + ci-test-result: + needs: [ci-test] + # Only run if the ci-test with matrices step is successful + if: always() + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Dump the client payload context + env: + PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} + run: echo "$PAYLOAD_CONTEXT" + + # Deleting the existing dir's if any + - name: Delete existing directories + if: needs.ci-test.result != 'success' + run: | + rm -f ~/failed_spec_ci + rm -f ~/combined_failed_spec_ci + + # Force store previous cypress dashboard url from cache + - name: Store the previous cypress dashboard url + continue-on-error: true + if: success() + uses: actions/cache@v3 + with: + path: | + ~/cypress_url + key: ${{ github.run_id }}-dashboard-url-${{ github.run_attempt }} + restore-keys: | + ${{ github.run_id }}-dashboard-url + + - name: Print cypress dashboard url + continue-on-error: true + id: dashboard_url + run: | + cypress_url="https://internal.appsmith.com/app/cypressdashboard/rundetails-64ec3df0c632e24c00764938?branch=master&workflowId=${{ github.run_id }}&attempt=${{ github.run_attempt }}" + echo "dashboard_url=$cypress_url" >> $GITHUB_OUTPUT + + # Download failed_spec list for all jobs + - uses: actions/download-artifact@v3 + if: needs.ci-test.result != 'success' + id: download_ci + with: + name: failed-spec-ci-${{github.run_attempt}} + path: ~/failed_spec_ci + + # In case for any ci job failure, create combined failed spec + - name: combine all specs for CI + id: combine_ci + if: needs.ci-test.result != 'success' + run: | + echo "Debugging: failed specs in ~/failed_spec_ci/failed_spec_ci*" + cat ~/failed_spec_ci/failed_spec_ci* + cat ~/failed_spec_ci/failed_spec_ci* | sort -u >> ~/combined_failed_spec_ci + if [[ -z $(grep '[^[:space:]]' ~/combined_failed_spec_ci) ]] ; then + echo "specs_failed=0" >> $GITHUB_OUTPUT + else + echo "specs_failed=1" >> $GITHUB_OUTPUT + fi + + # Upload combined failed CI spec list to a file + # This is done for debugging. + - name: upload combined failed spec + if: needs.ci-test.result != 'success' + uses: actions/upload-artifact@v3 + with: + name: combined_failed_spec_ci + path: ~/combined_failed_spec_ci + + - name: Get Latest flaky Tests + shell: bash + run: | + curl --request POST --url https://yatin-s-workspace-jk8ru5.us-east-1.xata.sh/db/CypressKnownFailures:main/tables/CypressKnownFailuires/query --header 'Authorization: Bearer ${{ secrets.XATA_TOKEN }}' --header 'Content-Type: application/json'|jq -r |grep Spec|cut -d ':' -f 2 2> /dev/null|sed 's/"//g'|sed 's/,//g' > ~/knownfailures + + # Verify CI test failures against known failures + - name: Verify CI test failures against known failures + if: needs.ci-test.result != 'success' + shell: bash + run: | + new_failed_spec_env="
      $(comm -1 -3 <(sort ~/knownfailures) <(sort -u ~/combined_failed_spec_ci) | sed 's/|cypress|cypress/\n/g' | sed 's/^/
    1. /')
    " + echo "$new_failed_spec_env" + echo "new_failed_spec_env<> $GITHUB_ENV + echo "$new_failed_spec_env" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Add a comment on the PR with new CI failures + if: needs.ci-test.result != 'success' && steps.combine_ci.outputs.specs_failed == '1' + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ github.event.client_payload.pull_request.number }} + body: | + Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. + Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`. + Cypress dashboard: Click here! + The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}} + To know the list of identified flaky tests - Refer here + + - name: Add a comment on the PR when ci-test is success + if: needs.ci-test.result == 'success' || steps.combine_ci.outputs.specs_failed == '0' + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ github.event.client_payload.pull_request.number }} + body: | + Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. + Commit: `${{ github.event.client_payload.slash_command.args.named.sha }}`. + Cypress dashboard: Click here! + All cypress tests have passed 🎉🎉🎉 + + # Update check run called "ci-test-result" + - name: Mark ci-test-result job as complete + uses: actions/github-script@v6 + id: update-check-run + if: ${{ always() }} + env: + run_id: ${{ github.run_id }} + repository: ${{ github.repository }} + number: ${{ github.event.client_payload.pull_request.number }} + job: ${{ github.job }} + # Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run + conclusion: ${{ job.status }} + matrix_result: ${{ toJson(needs.ci-test) }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { data: pull } = await github.rest.pulls.get({ + ...context.repo, + pull_number: process.env.number + }); + const ref = pull.head.sha; + + const { data: checks } = await github.rest.checks.listForRef({ + ...context.repo, + ref + }); + + const check = checks.check_runs.filter(c => c.name === process.env.job); + + if(check.length == 0) { + const head_sha = pull.head.sha; + const { data: completed_at } = await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head_sha: head_sha, + name: process.env.job, + status: 'completed', + conclusion: JSON.parse(process.env.matrix_result).result, + output: { + title: "Integration tests result for ok to test", + summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id + } + }); + + return completed_at; + } else { + try { + const { data: result } = await github.rest.checks.update({ + ...context.repo, + check_run_id: check[0].id, + status: 'completed', + conclusion: JSON.parse(process.env.matrix_result).result, + output: { + title: "Integration tests result for ok to test", + summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id + } + }); + console.log({ result }); + return result; + } catch(e) { + console.error({ error: e.message }); + } + } + + - name: Dump the client payload context + env: + PAYLOAD_CONTEXT: ${{ toJson(github.event.client_payload) }} + run: echo "$PAYLOAD_CONTEXT" + + - name: Check ci-test set status + if: needs.ci-test.result != 'success' + run: exit 1 + + package: + needs: [ci-test] + runs-on: ubuntu-latest + defaults: + run: + working-directory: app/client + # Run this job only if all the previous steps are a success and the reference if the release or master branch + if: success() && (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/master') + + steps: + # Update check run called "package" + - name: Mark package job as complete + uses: actions/github-script@v6 + id: update-check-run + if: ${{ always() }} + env: + run_id: ${{ github.run_id }} + repository: ${{ github.repository }} + number: ${{ github.event.client_payload.pull_request.number }} + job: ${{ github.job }} + # Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run + conclusion: ${{ job.status }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { data: pull } = await github.rest.pulls.get({ + ...context.repo, + pull_number: process.env.number + }); + const ref = pull.head.sha; + + const { data: checks } = await github.rest.checks.listForRef({ + ...context.repo, + ref + }); + + const check = checks.check_runs.filter(c => c.name === process.env.job); + + if(check.length == 0) { + const head_sha = pull.head.sha; + const { data: completed_at } = await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head_sha: head_sha, + name: process.env.job, + status: 'completed', + conclusion: process.env.conclusion, + output: { + title: "Package result for ok to test", + summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id + } + }); + + return completed_at; + } else { + const { data: result } = await github.rest.checks.update({ + ...context.repo, + check_run_id: check[0].id, + status: 'completed', + conclusion: process.env.conclusion, + output: { + title: "Package result for ok to test", + summary: "https://github.com/" + process.env.repository + "/actions/runs/" + process.env.run_id + } + }); + + return result; + } diff --git a/.github/workflows/ok-to-test-with-documentdb.yml b/.github/workflows/ok-to-test-with-documentdb.yml new file mode 100644 index 0000000000..3ed4ffdb93 --- /dev/null +++ b/.github/workflows/ok-to-test-with-documentdb.yml @@ -0,0 +1,33 @@ +# If someone with write access comments "/ok-to-test" on a pull request, emit a repository_dispatch event +name: Ok To Test with DocumentDB + +on: + issue_comment: + types: [created] + +jobs: + ok-to-test: + runs-on: ubuntu-latest + # Only run for PRs, not issue comments + if: | + github.event.issue.pull_request + steps: + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v1 + with: + app_id: ${{ secrets.APPSMITH_INTEGRATION_TESTING_ID }} + private_key: ${{ secrets.APPSMITH_INTEGRATION_TESTING_KEY }} + + - if: contains(github.event.comment.body, '/ok-to-test-with-documentdb') + name: Slash Command Dispatch + uses: peter-evans/slash-command-dispatch@v3 + env: + TOKEN: ${{ steps.generate_token.outputs.token }} + with: + token: ${{ env.TOKEN }} # GitHub App installation access token + reaction-token: ${{ secrets.GITHUB_TOKEN }} + issue-type: pull-request + commands: | + ok-to-test-with-documentdb + permission: write diff --git a/.github/workflows/on-demand-build-docker-image-deploy-preview.yml b/.github/workflows/on-demand-build-docker-image-deploy-preview.yml index b77f6e735d..3a6148c6ba 100644 --- a/.github/workflows/on-demand-build-docker-image-deploy-preview.yml +++ b/.github/workflows/on-demand-build-docker-image-deploy-preview.yml @@ -187,6 +187,7 @@ jobs: ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-dp:${{ vars.EDITION }}-${{ github.event.client_payload.pull_request.number }} build-args: | APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com + BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:release outputs: imageHash: ${{ vars.EDITION }}-${{ github.event.client_payload.pull_request.number }} @@ -207,23 +208,31 @@ jobs: ref: "refs/pull/${{ github.event.client_payload.pull_request.number }}/merge" fetch-depth: 0 + - name: Print versions of tools + run: | + set -o errexit + set -o xtrace + aws --version || true + kubectl version || true + helm version || true + - name: Install mongosh run: | + curl -fsSL https://pgp.mongodb.com/server-6.0.asc \ + | sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg --dearmor + echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" \ + | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list sudo apt-get update - sudo apt-get install -y wget gnupg - wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - - echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list - sudo apt-get update - sudo apt-get install -y mongodb-mongosh + sudo apt-get install --yes mongodb-mongosh + echo "MongoSH version: $(mongosh --version)" - name: Install relevant packages run: | - which aws - sudo apt update -q && sudo apt install -y curl unzip less jq - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.6/bin/linux/amd64/kubectl && \ - sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl && \ - curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \ - chmod 700 get_helm.sh; ./get_helm.sh + set -o errexit + # We still need Kubectl v1.23. Once we up the cluster version, we can get rid of this step. + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.23.6/bin/linux/amd64/kubectl + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + kubectl version || true - name: Deploy Helm chart env: @@ -241,7 +250,7 @@ jobs: DB_PASSWORD: ${{ secrets.DB_PASSWORD }} DB_URL: ${{ secrets.DB_URL }} DP_EFS_ID: ${{ secrets.APPSMITH_DP_EFS_ID }} - REDIS_URL: ${{ secrets.APPSMITH_DP_REDIS_URL }} + REDIS_URL: ${{ secrets.APPSMITH_DP_REDIS_URL }} run: | echo "environment variables set to deploy the image" $IMAGE_HASH /bin/bash ./scripts/deploy_preview.sh diff --git a/.github/workflows/perf-test-on-documentdb.yml b/.github/workflows/perf-test-on-documentdb.yml new file mode 100644 index 0000000000..034018cc10 --- /dev/null +++ b/.github/workflows/perf-test-on-documentdb.yml @@ -0,0 +1,259 @@ +name: Appsmith Performance Test (on DocumentDB) Workflow + +on: + # This line enables manual triggering of this workflow. + workflow_dispatch: + workflow_call: + inputs: + pr: + description: "This is the PR number in case the workflow is being called in a pull request" + required: false + type: number + +# Change the working directory for all the jobs in this workflow +defaults: + run: + working-directory: app/client + shell: bash + +jobs: + perf-test: + runs-on: ubuntu-latest-4-cores + # Only run this workflow for internally triggered events + if: | + github.event.pull_request.head.repo.full_name == github.repository || + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' || + github.event_name == 'repository_dispatch' + defaults: + run: + working-directory: app/client + shell: bash + + # Service containers to run with this job. Required for running tests + services: + # Label used to access the service container + redis: + # Docker Hub image for Redis + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + + steps: + - name: Checkout the merged commit from PR and base branch + if: inputs.pr != 0 + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: refs/pull/${{ inputs.pr }}/merge + + # Checkout the code in the current branch in case the workflow is called because of a branch push event + - name: Checkout the head commit of the branch + if: inputs.pr == 0 + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Figure out the PR number + run: echo ${{ inputs.pr }} + + - name: Print the Github event + run: echo ${{ github.event_name }} + + # Timestamp will be used to create cache key + - id: timestamp + run: echo "timestamp=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_OUTPUT + + # In case this is second attempt try restoring status of the prior attempt from cache + - name: Restore the previous run result + uses: actions/cache@v3 + with: + path: | + ~/run_result + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }}- + + # Fetch prior run result + - name: Get the previous run result + id: run_result + run: cat ~/run_result 2>/dev/null || echo 'default' + + # In case of prior failure run the job + - if: steps.run_result.outputs.run_result != 'success' + run: echo "I'm alive!" && exit 0 + + # Set status = success + - name: Save the status of the run + run: echo "run_result=success" >> $GITHUB_OUTPUT > ~/run_result + + # Set up Node.js cache yarn dependencies. + # actions/setup-node@v3 now support caching of dependencies using actions/cache under the hood + # https://github.com/actions/setup-node#caching-global-packages-data + - name: Set up Node.js + if: steps.run_result.outputs.run_result != 'success' + uses: actions/setup-node@v3 + with: + node-version-file: app/client/package.json + + - name: Download Docker image artifact + uses: actions/download-artifact@v3 + with: + name: cicontainer + + - name: Load Docker image from tar file + working-directory: "." + run: | + gunzip cicontainer.tar.gz + docker load -i cicontainer.tar + + - name: Create folder + if: steps.run_result.outputs.run_result != 'success' + env: + APPSMITH_LICENSE_KEY: ${{ secrets.APPSMITH_LICENSE_KEY }} + working-directory: "." + run: | + mkdir -p cicontainerlocal/stacks/configuration/ + + - name: Set up SSH key for tunnel + env: + SSH_PRIVATE_KEY: ${{ secrets.APPSMITH_CI_TUNNEL_PRIVATE_KEY }} + run: | + echo "$SSH_PRIVATE_KEY" > ssh_key.pem \ + chmod 600 ssh_key.pem + + - name: Setup SSH tunnel to AWS DocumentDB instance + run: | + ssh -4 -o StrictHostKeyChecking=no -o ServerAliveInterval=180 -o ServerAliveCountMax=5 -i "ssh_key.pem" -L 0.0.0.0:27010:docdb-ansible-test-cluster.cluster-cz8diybf9wdj.ap-south-1.docdb.amazonaws.com:27017 ubuntu@65.1.106.35 -N -f + + - name: Run docker image + if: steps.run_result.outputs.run_result != 'success' + env: + APPSMITH_LICENSE_KEY: ${{ secrets.APPSMITH_LICENSE_KEY }} + APPSMITH_MONGODB_URI: ${{ secrets.INTERNAL_CI_DOC_DB_URI }} + working-directory: "." + run: | + timestamp=$(date +%s) + hash=$(echo -n "$timestamp" | sha1sum | awk '{print $1}') + current_date=$(date -d "@$timestamp" +"%d-%m") + DB_NAME="ci${hash:1:3}-${current_date}" + mkdir -p ~/git-server/keys + mkdir -p ~/git-server/repos + docker run --name test-event-driver -d -p 2222:22 -p 5001:5001 -p 3306:3306 \ + -p 5432:5432 -p 28017:27017 -p 25:25 -p 5000:5000 -p 3000:3000 --privileged --pid=host --ipc=host --volume /:/host -v ~/git-server/keys:/git-server/keys \ + -v ~/git-server/repos:/git-server/repos appsmith/test-event-driver:latest + cd cicontainerlocal + docker run -d --name appsmith -p 80:80 -p 9001:9001 \ + -v "$PWD/stacks:/appsmith-stacks" -e APPSMITH_LICENSE_KEY=$APPSMITH_LICENSE_KEY \ + -e APPSMITH_DISABLE_TELEMETRY=true \ + -e APPSMITH_CLOUD_SERVICES_BASE_URL=http://host.docker.internal:5001 \ + -e APPSMITH_MONGODB_URI="${APPSMITH_MONGODB_URI}${DB_NAME}?retryWrites=false&replicaSet=rs0&directConnection=true" \ + --add-host=host.docker.internal:host-gateway \ + cicontainer + + # Start rts + - name: Start RTS Server + if: steps.run_result.outputs.run_result != 'success' + working-directory: ./app/client/packages/rts + run: | + cp .env.example .env + ./start-server.sh & + + - name: Setting up the perf tests + if: steps.run_result.outputs.run_result != 'success' + shell: bash + env: + APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} + APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} + CYPRESS_URL: ${{ secrets.CYPRESS_URL }} + CYPRESS_USERNAME: ${{ secrets.CYPRESS_USERNAME }} + CYPRESS_PASSWORD: ${{ secrets.CYPRESS_PASSWORD }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME1 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME2: ${{ secrets.CYPRESS_TESTUSERNAME2 }} + CYPRESS_TESTPASSWORD2: ${{ secrets.CYPRESS_TESTPASSWORD1 }} + CYPRESS_TESTUSERNAME3: ${{ secrets.CYPRESS_TESTUSERNAME3 }} + CYPRESS_TESTPASSWORD3: ${{ secrets.CYPRESS_TESTPASSWORD3 }} + CYPRESS_TESTUSERNAME4: ${{ secrets.CYPRESS_TESTUSERNAME4 }} + CYPRESS_TESTPASSWORD4: ${{ secrets.CYPRESS_TESTPASSWORD4 }} + CYPRESS_S3_ACCESS_KEY: ${{ secrets.CYPRESS_S3_ACCESS_KEY }} + CYPRESS_S3_SECRET_KEY: ${{ secrets.CYPRESS_S3_SECRET_KEY }} + CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET }} + CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_ID }} + CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: ${{ secrets.CYPRESS_APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET }} + APPSMITH_DISABLE_TELEMETRY: true + APPSMITH_GOOGLE_MAPS_API_KEY: ${{ secrets.APPSMITH_GOOGLE_MAPS_API_KEY }} + POSTGRES_PASSWORD: postgres + run: | + chmod a+x ./perf/setup-perf-test.sh + ./perf/setup-perf-test.sh + + - name: Get the performance-infra branch/ref + id: perf_infra_ref + run: | + ref=${{ github.event.client_payload.slash_command.args.named.ref }} + if [[ -z "$ref" ]]; then ref="main"; fi + echo ref=$ref >> $GITHUB_OUTPUT + + - name: Checkout Performance Infra code + uses: actions/checkout@v3 + with: + repository: appsmithorg/performance-infra + token: ${{ secrets.APPSMITH_PERF_INFRA_REPO_PAT }} + ref: ${{ steps.perf_infra_ref.outputs.ref }} + path: perf + + - name: Installing performance tests dependencies + if: steps.run_result.outputs.run_result != 'success' + working-directory: perf + shell: bash + run: yarn install --frozen-lockfile + + - name: Change test script permissions + if: steps.run_result.outputs.run_result != 'success' + working-directory: perf + run: chmod +x ./start-test.sh + + - name: Run performance tests + if: steps.run_result.outputs.run_result != 'success' + working-directory: perf + shell: bash + env: + APPSMITH_SSL_CERTIFICATE: ${{ secrets.APPSMITH_SSL_CERTIFICATE }} + APPSMITH_SSL_KEY: ${{ secrets.APPSMITH_SSL_KEY }} + CYPRESS_TESTUSERNAME1: ${{ secrets.CYPRESS_TESTUSERNAME9 }} + CYPRESS_TESTPASSWORD1: ${{ secrets.CYPRESS_TESTPASSWORD9 }} + APPSMITH_PERFORMANCE_DB_CONFIG: ${{ secrets.APPSMITH_PERFORMANCE_DB_CONFIG }} + APPSMITH_PERFORMANCE_S3_KEY: ${{secrets.APPSMITH_PERFORMANCE_S3_KEY}} + APPSMITH_PERFORMANCE_S3_SECRET: ${{secrets.APPSMITH_PERFORMANCE_S3_SECRET}} + APPSMITH_PERFORMANCE_DB_PASSWORD: ${{secrets.APPSMITH_PERFORMANCE_DB_PASSWORD}} + APPSMITH_PERFORMANCE_DB_HOST: ${{secrets.APPSMITH_PERFORMANCE_DB_HOST}} + APPSMITH_PERFORMANCE_DB_V2_CONFIG: ${{ secrets.APPSMITH_PERFORMANCE_DB_V2_CONFIG }} + PERF_GITHUB_PAT: ${{ secrets.APPSMITH_PERF_INFRA_REPO_PAT }} + APPSMITH_DISABLE_TELEMETRY: true + POSTGRES_PASSWORD: postgres + NODE_TLS_REJECT_UNAUTHORIZED: "0" + MACHINE: ubuntu-latest-4-cores + + run: ./start-test.sh + + # Restore the previous built bundle if present. If not push the newly built into the cache + - name: Restore the previous bundle + uses: actions/cache@v3 + with: + path: | + perf/traces + key: ${{ github.run_id }}-${{ github.job }}-${{ steps.timestamp.outputs.timestamp }} + restore-keys: | + ${{ github.run_id }}-${{ github.job }} + + - uses: actions/upload-artifact@v3 + with: + name: performance-test-logs + path: perf/traces/reports + + # Set status = success + - name: Save the status of the run + run: echo "run_result=success" >> $GITHUB_OUTPUT > ~/run_result diff --git a/.github/workflows/perf-test-v2.yml b/.github/workflows/perf-test-v2.yml index dc5155b511..dea2deac57 100644 --- a/.github/workflows/perf-test-v2.yml +++ b/.github/workflows/perf-test-v2.yml @@ -29,6 +29,11 @@ jobs: run: working-directory: app/client shell: bash + + strategy: + fail-fast: false + matrix: + job: [0, 1] # Service containers to run with this job. Required for running tests services: @@ -222,6 +227,7 @@ jobs: POSTGRES_PASSWORD: postgres NODE_TLS_REJECT_UNAUTHORIZED: "0" MACHINE: ubuntu-latest-4-cores + JOB: ${{ matrix.job }} run: ./start-test.sh diff --git a/.github/workflows/perf-tests-command.yml b/.github/workflows/perf-tests-command.yml index 2114a5b1f9..dc4266b738 100644 --- a/.github/workflows/perf-tests-command.yml +++ b/.github/workflows/perf-tests-command.yml @@ -60,3 +60,13 @@ jobs: secrets: inherit with: pr: ${{ github.event.client_payload.pull_request.number }} + + perf-test-v2: + needs: [ build-docker-image ] + # Only run if the build step is successful + if: success() + name: perf-test-v2 + uses: ./.github/workflows/perf-test-v2.yml + secrets: inherit + with: + pr: ${{ github.event.client_payload.pull_request.number }} \ No newline at end of file diff --git a/.github/workflows/rts-build.yml b/.github/workflows/rts-build.yml index 8c8c3f8081..f131f4d456 100644 --- a/.github/workflows/rts-build.yml +++ b/.github/workflows/rts-build.yml @@ -69,9 +69,6 @@ jobs: - name: Print the Github event run: echo ${{ github.event_name }} - - name: Set up Depot CLI - uses: depot/setup-action@v1 - # In case this is second attempt try restoring status of the prior attempt from cache - name: Restore the previous run result uses: actions/cache@v3 diff --git a/.github/workflows/server-build.yml b/.github/workflows/server-build.yml index 95864330fa..12d14c5c67 100644 --- a/.github/workflows/server-build.yml +++ b/.github/workflows/server-build.yml @@ -131,6 +131,7 @@ jobs: ACTIVE_PROFILE: test APPSMITH_MONGODB_URI: "mongodb://localhost:27017/mobtools" APPSMITH_CLOUD_SERVICES_BASE_URL: "https://release-cs.appsmith.com" + APPSMITH_CLOUD_SERVICES_TEMPLATE_UPLOAD_AUTH: ${{ secrets.APPSMITH_CLOUD_SERVICES_TEMPLATE_UPLOAD_AUTH }} APPSMITH_REDIS_URL: "redis://127.0.0.1:6379" APPSMITH_ENCRYPTION_PASSWORD: "password" APPSMITH_ENCRYPTION_SALT: "salt" diff --git a/.github/workflows/test-build-docker-image.yml b/.github/workflows/test-build-docker-image.yml index 8d409d0ce1..68c7b22110 100644 --- a/.github/workflows/test-build-docker-image.yml +++ b/.github/workflows/test-build-docker-image.yml @@ -45,16 +45,6 @@ jobs: with: pr: 0 - perf-test: - needs: [build-docker-image] - # Only run if the build step is successful - if: success() - name: perf-test - uses: ./.github/workflows/perf-test.yml - secrets: inherit - with: - pr: 0 - ci-test: needs: [build-docker-image] # Only run if the build step is successful @@ -106,7 +96,7 @@ jobs: if: needs.ci-test.result != 'success' shell: bash run: | - new_failed_spec_env="
      $(sort -u ~/combined_failed_spec_ci | sed 's/|cypress|cypress/\n/g' | sed 's/^/
    1. /')
    " + new_failed_spec_env="
      $(sort -u ~/combined_failed_spec_ci | sed 's/|cypress|cypress/<\/li>\n
    1. /g' | sed -e 's/^
    2. //' -e 's/<\/li>$//' -e 's/<\/li>/<\/li>\n/')
    " echo "$new_failed_spec_env" echo "new_failed_spec_env<> $GITHUB_ENV echo "$new_failed_spec_env" >> $GITHUB_ENV @@ -116,13 +106,23 @@ jobs: continue-on-error: true if: always() id: slack_notification + env: + EVENT_COMMITS: ${{ toJson(github.event.commits[0].message) }} run: | - if [[ "${{ needs.ci-test.result }}" != "success" ]]; then - echo "slack_message=There are test failures in the run.
    ${{env.new_failed_spec_env}}
    Please check the <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Github Actions> for more details." >> $GITHUB_OUTPUT + eventCommit=$(echo ${{env.EVENT_COMMITS}} | sed "s/'//g") + echo "slack_username=$(echo "$eventCommit" | awk -F '\\\\n' '{print $1}' | sed 's/^"//;s/"$//')" >> $GITHUB_OUTPUT + if [[ ${{ needs.ci-test.result }} == 'failure' ]]; then + echo "slack_message=There are test failures in the run. Cypress Dashboard: " >> $GITHUB_OUTPUT echo "slack_color=#FF0000" >> $GITHUB_OUTPUT - else - echo "slack_message=All tests passed successfully :tada: . Github Action: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Click here!>" >> $GITHUB_OUTPUT + echo "slack_icon=:no_entry:" >> $GITHUB_OUTPUT + elif [[ ${{ needs.ci-test.result }} == 'success' ]]; then + echo "slack_message=All tests passed successfully :tada: Cypress Dashboard: " >> $GITHUB_OUTPUT echo "slack_color=#00FF00" >> $GITHUB_OUTPUT + echo "slack_icon=:white_check_mark:" >> $GITHUB_OUTPUT + else + echo "slack_message=There are build failures. To analyze run go <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|here>" >> $GITHUB_OUTPUT + echo "slack_color=#FF0000" >> $GITHUB_OUTPUT + echo "slack_icon=:warning:" >> $GITHUB_OUTPUT fi - name: Slack Notification @@ -132,12 +132,13 @@ jobs: env: SLACK_CHANNEL: cypresspushworkflow SLACK_COLOR: ${{steps.slack_notification.outputs.slack_color}} + SLACK_ICON_EMOJI: ${{steps.slack_notification.outputs.slack_icon}} SLACK_ICON: https://app.slack.com/services/B05D17E4QVB - SLACK_TITLE: 'Result:' - SLACK_USERNAME: Cypress Push Workflows + SLACK_TITLE: "Result:" + SLACK_USERNAME: ${{steps.slack_notification.outputs.slack_username}} SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_HOSTED }} MSG_MINIMAL: Ref,Event,Commit - SLACK_FOOTER: 'Appsmith Push Workflows' + SLACK_FOOTER: "Push Workflow" SLACK_MESSAGE: ${{steps.slack_notification.outputs.slack_message}} # Force save the CI failed spec list into a cache @@ -173,7 +174,6 @@ jobs: exit 1; fi - package-release: needs: build-docker-image runs-on: ubuntu-latest @@ -220,6 +220,12 @@ jobs: echo "Cleaning up the tar files" rm app/client/packages/rts/dist/rts-dist.tar + - name: Generate info.json + run: | + if [[ -f scripts/generate_info_json.sh ]]; then + scripts/generate_info_json.sh + fi + - name: Set up Depot CLI uses: depot/setup-action@v1 @@ -239,6 +245,7 @@ jobs: build-args: | APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY_RELEASE }} APPSMITH_CLOUD_SERVICES_BASE_URL=https://release-cs.appsmith.com + BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:release tags: | ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:release @@ -288,6 +295,12 @@ jobs: echo "Cleaning up the tar files" rm app/client/packages/rts/dist/rts-dist.tar + - name: Generate info.json + run: | + if [[ -f scripts/generate_info_json.sh ]]; then + scripts/generate_info_json.sh + fi + - name: Set up Depot CLI uses: depot/setup-action@v1 @@ -306,6 +319,44 @@ jobs: platforms: linux/arm64,linux/amd64 build-args: | APPSMITH_SEGMENT_CE_KEY=${{ secrets.APPSMITH_SEGMENT_CE_KEY }} + BASE=${{ vars.DOCKER_HUB_ORGANIZATION }}/base-${{ vars.EDITION }}:nightly tags: | ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:${{ github.sha }} ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:nightly + + notify-slack-for-promotion: + needs: ci-test + runs-on: ubuntu-latest + + if: ( failure() && github.ref == 'refs/heads/master' ) + + steps: + - name: Notify failure on workflow run and on Slack + run: | + set -o errexit + set -o nounset + set -o xtrace + + run_url='${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}' + common_parent_sha='${{ steps.merge.outputs.common_parent_sha }}' + common_parent_sha_short="$(echo "$common_parent_sha" | grep -o '^.\{8\}' || true)" + merged_upto_sha='${{ steps.merge.outputs.merged_upto_sha }}' + merged_upto_sha_short="$(echo "$merged_upto_sha" | grep -o '^.\{8\}' || true)" + + details="🚨 TBP workflow failed in <$run_url|${{ github.run_id }}/attempts/${{ github.run_attempt }}>. + + # This unweildy horror of a sed command, converts standard Markdown links to Slack's unweildy link syntax. + slack_message="$(echo "$details" | sed -E 's/\[([^]]+)\]\(([^)]+)\)/<\2|\1>/g')" + + # This is the ChannelId of the tech channel. + body="$(jq -nc \ + --arg channel CGBPVEJ5C \ + --arg text "$slack_message" \ + '$ARGS.named' + )" + + curl -v https://slack.com/api/chat.postMessage \ + --fail-with-body \ + --header 'Authorization: Bearer ${{ secrets.SLACK_APPSMITH_ALERTS_TOKEN }}' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data-raw "$body" diff --git a/.github/workflows/upgrade-appsmith-tests.yml b/.github/workflows/upgrade-appsmith-tests.yml index df708c5a44..e0628ea5f2 100644 --- a/.github/workflows/upgrade-appsmith-tests.yml +++ b/.github/workflows/upgrade-appsmith-tests.yml @@ -121,4 +121,4 @@ jobs: - name: Check ci-test set status if: needs.ci-test.result != 'success' - run: exit 1 + run: exit 1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7d4a66c948..e4d146b252 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ app/client/cypress.env.json dist stacks -/info.json +/deploy/docker/fs/opt/appsmith/info.json # to ignore the node_modeules folder node_modules diff --git a/CODEOWNERS b/CODEOWNERS index 54b28e1262..0124f366ae 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -23,12 +23,12 @@ app/client/tsconfig.json @KelvinOm app/client/tsconfig.path.json @KelvinOm # App viewers pod -app/client/src/widgets/* @appsmithorg/app-viewers @rajatagrawal +app/client/src/widgets/* @appsmithorg/app-viewers app/client/cypress/e2e/Regression/ClientSide/Widgets/* @rajatagrawal app/client/src/components/propertyControls/* @appsmithorg/app-viewers -app/client/src/sagas/OneClickBindingSaga.ts @sbalaji1192 @berzerkeer -app/client/src/WidgetQueryGenerators/* @sbalaji1192 @berzerkeer -app/client/src/components/editorComponents/WidgetQueryGeneratorForm/* @sbalaji1192 @berzerkeer +app/client/src/sagas/OneClickBindingSaga.ts @sbalaji1192 +app/client/src/WidgetQueryGenerators/* @sbalaji1192 +app/client/src/components/editorComponents/WidgetQueryGeneratorForm/* @sbalaji1192 app/client/src/pages/AppViewer/* @appsmithorg/app-viewers app/client/src/pages/Editor/AppSettingsPane/AppSettings/NavigationSettings/* @dhruvikn app/client/src/ce/pages/AppViewer/NavigationLogo.tsx @dhruvikn @@ -63,26 +63,16 @@ app/client/src/actions/autoLayoutActions.ts @appsmithorg/ui-builders app/client/src/actions/canvasSelectionActions.ts @appsmithorg/ui-builders app/client/src/actions/reflowActions.ts @appsmithorg/ui-builders app/client/src/actions/widgetSelectionActions.ts @appsmithorg/ui-builders -app/client/src/components/autoHeight/* @appsmithorg/ui-builders -app/client/src/components/autoHeightOverlay/* @appsmithorg/ui-builders -app/client/src/components/designSystems/appsmith/PositionedContainer.tsx @appsmithorg/ui-builders -app/client/src/components/editorComponents/DraggableComponent.tsx @appsmithorg/ui-builders -app/client/src/components/editorComponents/ResizableComponent.tsx @appsmithorg/ui-builders -app/client/src/components/editorComponents/ResizableUtils.ts @appsmithorg/ui-builders -app/client/src/components/editorComponents/ResizeStyledComponents.tsx @appsmithorg/ui-builders -app/client/src/components/editorComponents/WidgetNameComponent/* @appsmithorg/ui-builders app/client/src/components/propertyControls/* @appsmithorg/ui-builders +app/client/src/layoutSystems/* @appsmithorg/ui-builders app/client/src/normalizers/CanvasWidgetsNormalizer.tsx @appsmithorg/ui-builders app/client/src/pages/Editor/Canvas.tsx @appsmithorg/ui-builders app/client/src/pages/Editor/CanvasLayoutConversion/* @appsmithorg/ui-builders app/client/src/pages/Editor/PropertyPane/* @appsmithorg/ui-builders -app/client/src/pages/Editor/WidgetsMultiSelectBox.tsx @appsmithorg/ui-builders -app/client/src/pages/common/CanvasArenas/* @appsmithorg/ui-builders app/client/src/reducers/entityReducers/autoHeightReducers/* @appsmithorg/ui-builders app/client/src/reducers/entityReducers/canvasWidgetsReducer.ts @appsmithorg/ui-builders app/client/src/reducers/entityReducers/widgetConfigReducer.ts @appsmithorg/ui-builders app/client/src/reflow/* @appsmithorg/ui-builders -app/client/src/resizable/* @appsmithorg/ui-builders app/client/src/sagas/AutoLayoutUpdateSagas.tsx @appsmithorg/ui-builders app/client/src/sagas/CanvasSagas/* @appsmithorg/ui-builders app/client/src/sagas/ReplaySaga.ts @appsmithorg/ui-builders @@ -102,7 +92,6 @@ app/client/src/selectors/canvasSelectors.ts @appsmithorg/ui-builders app/client/src/selectors/widgetSelectors.ts @appsmithorg/ui-builders app/client/src/utils/DSLConversions/* @appsmithorg/ui-builders app/client/src/utils/autoHeight/* @appsmithorg/ui-builders -app/client/src/utils/autoLayout/* @appsmithorg/ui-builders app/client/src/utils/hooks/autoHeightUIHooks.ts @appsmithorg/ui-builders app/client/src/utils/hooks/useAllowEditorDragToSelect.ts @appsmithorg/ui-builders app/client/src/utils/hooks/useClickToSelectWidget.tsx @appsmithorg/ui-builders @@ -111,7 +100,7 @@ app/client/src/utils/hooks/usePositionedContainerZIndex.ts @appsmithorg/ui-build app/client/src/utils/hooks/useReflow.ts @appsmithorg/ui-builders app/client/src/utils/hooks/useWidgetSelection.ts @appsmithorg/ui-builders app/client/src/widgets/BaseWidget.tsx @appsmithorg/ui-builders -app/client/src/widgets/CanvasResizer.tsx @appsmithorg/ui-builders +app/client/src/widgets/BaseWidgetHOC/* @appsmithorg/ui-builders app/client/src/widgets/CanvasWidget.tsx @appsmithorg/ui-builders app/client/src/widgets/ContainerWidget/* @appsmithorg/ui-builders app/client/src/widgets/MetaHOC.tsx @appsmithorg/ui-builders @@ -132,82 +121,115 @@ app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitUtils.ja # Data Platform -app/client/src/actions/datasourceActions.ts @ayushpahwa @ChandanBalajiBP -app/client/src/api/ActionAPI.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/ce/components/DSDataFilter/index.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/ce/constants/ReduxActionConstants.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/ce/sagas/ApplicationSagas.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/ce/selectors/environmentSelectors.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/ce/utils/Environments/index.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/components/BottomBar/index.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/components/formControls/utils.test.ts @ayushpahwa @ChandanBalajiBP -app/client/src/components/formControls/utils.ts @ayushpahwa @ChandanBalajiBP -app/client/src/entities/Datasource/index.ts @ayushpahwa @ChandanBalajiBP -app/client/src/entities/FeatureFlags.ts @ayushpahwa @ChandanBalajiBP -app/client/src/navigation/FocusEntity.ts @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/APIEditor/* @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/DataSourceEditor/* @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/SaaSEditor/DatasourceCard.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/pages/common/datasourceAuth/index.tsx @ayushpahwa @ChandanBalajiBP -app/client/src/reducers/entityReducers/datasourceReducer.ts @ayushpahwa @ChandanBalajiBP -app/client/src/sagas/ActionExecution/PluginActionSaga.ts @ayushpahwa @ChandanBalajiBP -app/client/src/sagas/DatasourcesSagas.ts @ayushpahwa @ChandanBalajiBP -app/client/src/sagas/QueryPaneSagas.ts @ayushpahwa @ChandanBalajiBP -app/client/src/transformers/RestAPIDatasourceFormTransformer.ts @ayushpahwa @ChandanBalajiBP +app/client/src/actions/datasourceActions.ts @ayushpahwa +app/client/src/api/ActionAPI.tsx @ayushpahwa +app/client/src/ce/components/DSDataFilter/index.tsx @ayushpahwa +app/client/src/ce/constants/ReduxActionConstants.tsx @ayushpahwa +app/client/src/ce/sagas/ApplicationSagas.tsx @ayushpahwa +app/client/src/ce/selectors/environmentSelectors.tsx @ayushpahwa +app/client/src/ce/utils/Environments/index.tsx @ayushpahwa +app/client/src/components/BottomBar/index.tsx @ayushpahwa +app/client/src/components/editorComponents/form/fields/EmbeddedDatasourcePathField.tsx @ayushpahwa +app/client/src/components/formControls/utils.test.ts @ayushpahwa +app/client/src/components/formControls/utils.ts @ayushpahwa +app/client/src/entities/Datasource/index.ts @ayushpahwa +app/client/src/entities/FeatureFlags.ts @ayushpahwa +app/client/src/navigation/FocusEntity.ts @ayushpahwa +app/client/src/pages/Editor/APIEditor/* @ayushpahwa +app/client/src/pages/Editor/DataSourceEditor/* @ayushpahwa +app/client/src/pages/Editor/IntegrationEditor/DatasourceCard.tsx @ayushpahwa +app/client/src/pages/Editor/IntegrationEditor/IntegrationsHomeScreen.tsx @ayushpahwa +app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx @ayushpahwa +app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @ayushpahwa +app/client/src/pages/Editor/SaaSEditor/DatasourceCard.tsx @ayushpahwa +app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx @ayushpahwa +app/client/src/pages/Editor/gitSync/ReconnectDatasourceModal.tsx @ayushpahwa +app/client/src/pages/common/datasourceAuth/index.tsx @ayushpahwa +app/client/src/reducers/entityReducers/datasourceReducer.ts @ayushpahwa +app/client/src/sagas/ActionExecution/PluginActionSaga.ts @ayushpahwa +app/client/src/sagas/DatasourcesSagas.ts @ayushpahwa +app/client/src/sagas/QueryPaneSagas.ts @ayushpahwa +app/client/src/transformers/RestAPIDatasourceFormTransformer.ts @ayushpahwa # Followed Globstar paths in combination with wildcard paths. Reference https://docs.gitlab.com/ee/user/project/codeowners/reference.html#globstar-paths # Data Platform server - Interfaces -app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Action* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Datasource* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/OAuth2* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Action* @nidhi-nair @sondermanish +app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/Datasource* @nidhi-nair @sondermanish +app/server/appsmith-interfaces/src/main/java/com/appsmith/external/**/OAuth2* @nidhi-nair @sondermanish # Data Platform server - Controllers -app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Action* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Datasource* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Action* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/**/Datasource* @nidhi-nair @sondermanish # Data Platform server - Domains -app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Action* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Datasource* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Action* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/domains/**/Datasource* @nidhi-nair @sondermanish # Data Platform server - DTOs -app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Action* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Datasource* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Action* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/**/Datasource* @nidhi-nair @sondermanish # Data Platform server - Repositories -app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Action* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Datasource* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Action* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/**/*Datasource* @nidhi-nair @sondermanish # Data Platform server - Services -app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Action* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Datasource* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Authentication* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Action* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Datasource* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/services/**/*Authentication* @nidhi-nair @sondermanish # Data Platform server - Solutions -app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Action* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Datasource* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Authentication* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Environment* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Action* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Datasource* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Authentication* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/**/*Environment* @nidhi-nair @sondermanish # Data Platform server - Misc -app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/**/Datasource* @nidhi-nair @sondermanish @tkappsmith -app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError* @nidhi-nair @sondermanish @tkappsmith +app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/**/Datasource* @nidhi-nair @sondermanish +app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError* @nidhi-nair @sondermanish # Team Managers pod -app/client/src/ce/* @ankitakinger -app/client/src/ee/* @ankitakinger -app/client/src/pages/Settings/* @ankitakinger -app/client/cypress/e2e/Regression/Enterprise/* @ankitakinger -app/client/cypress/e2e/Regression/EE/Enterprise/* @ankitakinger -app/client/cypress/e2e/Regression/ClientSide/AdminSettings/* @ankitakinger -app/client/cypress/e2e/Regression/ClientSide/Google/* @ankitakinger -app/client/cypress/e2e/Regression/ClientSide/Github/* @ankitakinger -app/client/cypress/e2e/Regression/ClientSide/FormLogin/* @ankitakinger -app/client/cypress/e2e/Regression/ClientSide/Auditlogs/* @ankitakinger +app/client/src/pages/Settings/**/* @ankitakinger +app/client/src/pages/workspace/settings.tsx @ankitakinger +app/client/src/pages/workspace/AppInviteUsersForm.tsx @ankitakinger +app/client/src/pages/workspace/WorkspaceInviteUsersForm.tsx @ankitakinger +app/client/src/components/editorComponents/form/FormDialogComponent.tsx @ankitakinger +app/client/src/ce/pages/AdminSettings/**/* @ankitakinger +app/client/src/ee/pages/AdminSettings/**/* @ankitakinger +app/client/src/ce/pages/Applications/EmbedSnippetTab.tsx @ankitakinger +app/client/src/ee/pages/Applications/EmbedSnippetTab.tsx @ankitakinger +app/client/src/ce/pages/Applications/PrivateEmbedSettings.tsx @ankitakinger +app/client/src/ee/pages/Applications/PrivateEmbedSettings.tsx @ankitakinger +app/client/src/ce/pages/workspace/Members.tsx @ankitakinger +app/client/src/ee/pages/workspace/Members.tsx @ankitakinger +app/client/src/ce/pages/workspace/InviteUsersForm.tsx @ankitakinger +app/client/src/ee/pages/workspace/InviteUsersForm.tsx @ankitakinger +app/client/src/ce/pages/Upgrade/**/* @ankitakinger +app/client/src/ee/pages/Auditlogs/**/* @ankitakinger +app/client/cypress/e2e/Regression/Enterprise/**/* @ankitakinger +app/client/cypress/e2e/Regression/EE/Enterprise/**/* @ankitakinger +app/client/cypress/e2e/Regression/ClientSide/AdminSettings/**/* @ankitakinger +app/client/cypress/e2e/Regression/ClientSide/Google/**/* @ankitakinger +app/client/cypress/e2e/Regression/ClientSide/Github/**/* @ankitakinger +app/client/cypress/e2e/Regression/ClientSide/FormLogin/**/* @ankitakinger +app/client/cypress/e2e/Regression/ClientSide/Auditlogs/**/* @ankitakinger + +#FE pod +app/client/src/actions/evaluationActions.ts @ApekshaBhosale +app/client/src/ce/entities/DataTree/**/* @ApekshaBhosale +app/client/src/ce/entities/DependencyMap/**/* @ApekshaBhosale +app/client/src/ce/entities/workers/**/* @ApekshaBhosale +app/client/src/ee/entities/DataTree* @ApekshaBhosale +app/client/src/ee/entities/workers/**/* @ApekshaBhosale +app/client/src/sagas/EvaluationsSaga.ts @ApekshaBhosale +app/client/src/sagas/EvalWorkerActionSagas.ts @ApekshaBhosale +app/client/src/sagas/LintingSagas.ts @ApekshaBhosale +app/client/src/sagas/PostEvaluationSags.ts @ApekshaBhosale +app/client/src/sagas/PostLintingSagas.ts @ApekshaBhosale +app/client/src/workers/**/* @ApekshaBhosale +app/client/src/sagas/JSLibrarySaga.ts @ApekshaBhosale +app/client/src/ce/ActionExecution/ActionExecutionSagas.ts @ApekshaBhosale +app/client/src/ee/ActionExecution/ActionExecutionSagas.ts @ApekshaBhosale +app/client/src/ce/JSFunctionExecutionSaga.ts @ApekshaBhosale +app/client/src/ee/JSFunctionExecutionSaga.ts @ApekshaBhosale diff --git a/Dockerfile b/Dockerfile index 91e97708f0..9c595877c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,9 @@ ENV APPSMITH_CLOUD_SERVICES_BASE_URL=${APPSMITH_CLOUD_SERVICES_BASE_URL} ARG APPSMITH_SEGMENT_CE_KEY ENV APPSMITH_SEGMENT_CE_KEY=${APPSMITH_SEGMENT_CE_KEY} #Create the plugins directory -RUN mkdir -p ./backend ./editor ./rts ./backend/plugins ./templates ./utils +RUN mkdir -p ./editor ./rts ./backend/plugins + +COPY deploy/docker/fs / #Add the jar to the container COPY ${JAR_FILE} backend/server.jar @@ -24,45 +26,19 @@ COPY ${PLUGIN_JARS} backend/plugins/ COPY ./app/client/build editor/ # Add RTS - Application Layer -COPY ./app/client/packages/rts/package.json ./app/client/packages/rts/dist rts/ +COPY ./app/client/packages/rts/dist rts/ -# Nginx, MongoDB and PostgreSQL data config template - Configuration layer -COPY ./deploy/docker/templates/nginx/* \ - ./deploy/docker/templates/docker.env.sh \ - ./deploy/docker/templates/mockdb_postgres.sql \ - ./deploy/docker/templates/users_postgres.sql \ - ./deploy/docker/templates/appsmith_starting.html \ - ./deploy/docker/templates/appsmith_initializing.html \ - templates/ +ENV PATH /opt/appsmith/utils/node_modules/.bin:/opt/java/bin:/opt/node/bin:$PATH -# Add bootstrapfile -COPY ./deploy/docker/entrypoint.sh ./deploy/docker/scripts/* info.*json ./ +RUN cd ./utils && npm install --only=prod && npm install --only=prod -g . && cd - \ + && chmod 0644 /etc/cron.d/* \ + && chmod +x *.sh templates/nginx-app.conf.sh /watchtower-hooks/*.sh \ + # Disable setuid/setgid bits for the files inside container. + && find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true \ + && node prepare-image.mjs -# Add util tools -COPY ./deploy/docker/utils ./utils -RUN cd ./utils && npm install --only=prod && npm install --only=prod -g . - -# Add process config to be run by supervisord -COPY ./deploy/docker/templates/supervisord.conf /etc/supervisor/supervisord.conf -COPY ./deploy/docker/templates/supervisord/ templates/supervisord/ - -# Add defined cron job -COPY ./deploy/docker/templates/cron.d /etc/cron.d/ -RUN chmod 0644 /etc/cron.d/* - -RUN chmod +x entrypoint.sh renew-certificate.sh healthcheck.sh - -# Disable setuid/setgid bits for the files inside container. -RUN find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true - -# Update path to load appsmith utils tool as default -ENV PATH /opt/appsmith/utils/node_modules/.bin:$PATH LABEL com.centurylinklabs.watchtower.lifecycle.pre-check=/watchtower-hooks/pre-check.sh LABEL com.centurylinklabs.watchtower.lifecycle.pre-update=/watchtower-hooks/pre-update.sh -COPY ./deploy/docker/watchtower-hooks /watchtower-hooks -RUN chmod +x /watchtower-hooks/pre-check.sh -RUN chmod +x /watchtower-hooks/pre-update.sh - EXPOSE 80 EXPOSE 443 diff --git a/app.json b/app.json index 6e36849a69..8cf39b5f7d 100644 --- a/app.json +++ b/app.json @@ -31,7 +31,7 @@ "value": "" }, "APPSMITH_DISABLE_TELEMETRY": { - "description" : "We want to be transparent and request that you share anonymous usage data with us. This data is purely statistical in nature and helps us understand your needs & provide better support to your self-hosted instance. You can read more about what information is collected in our documentation https://docs.appsmith.com/v/v1.2.1/setup/telemetry", + "description" : "We want to be transparent and request that you share anonymous usage data with us. This data is purely statistical in nature and helps us understand your needs & provide better support to your self-hosted instance. You can read more about what information is collected in our documentation https://docs.appsmith.com/product/telemetry", "value": "false" }, "APPSMITH_SUPERVISOR_PASSWORD": { diff --git a/app/client/.eslintrc.base.json b/app/client/.eslintrc.base.json index b95a7b7fef..bc36b1d284 100644 --- a/app/client/.eslintrc.base.json +++ b/app/client/.eslintrc.base.json @@ -2,6 +2,12 @@ "$schema": "http://json.schemastore.org/eslintrc", "root": true, "parser": "@typescript-eslint/parser", + "ignorePatterns": [ + "jest.config.js", + "jest.setup.ts", + "rollup.config.js", + ".eslintrc.js" + ], "plugins": [ "react", "@typescript-eslint", @@ -22,9 +28,14 @@ "sourceType": "module", "ecmaFeatures": { "jsx": true - } + }, + "project": "./tsconfig.json" }, "rules": { + "@typescript-eslint/consistent-type-definitions": "error", + "@typescript-eslint/prefer-nullish-coalescing": "error", + "@typescript-eslint/promise-function-async": "error", + "@typescript-eslint/strict-boolean-expressions": "error", "@typescript-eslint/no-explicit-any": "error", "@typescript-eslint/no-unused-vars": "warn", "jest/no-focused-tests": "error", diff --git a/app/client/.eslintrc.js b/app/client/.eslintrc.js index 282ba466c8..3d9baabbb8 100644 --- a/app/client/.eslintrc.js +++ b/app/client/.eslintrc.js @@ -13,6 +13,8 @@ const baseNoRestrictedImports = const eslintConfig = { extends: [".eslintrc.base.json"], rules: { + "@typescript-eslint/prefer-nullish-coalescing": "off", + "@typescript-eslint/strict-boolean-expressions": "off", "@typescript-eslint/no-explicit-any": "off", "react/display-name": "off", "react/prop-types": "off", @@ -86,6 +88,9 @@ const eslintConfig = { }, ], }, + parserOptions: { + tsconfigRootDir: __dirname, + }, }; eslintConfig.overrides = [ diff --git a/app/client/.gitignore b/app/client/.gitignore index b32680884f..1082b216bf 100755 --- a/app/client/.gitignore +++ b/app/client/.gitignore @@ -38,6 +38,7 @@ cypress/videos cypress/screenshots cypress/limited-tests.txt cypress.env.json +cypress/cypress-logs results/ diff --git a/app/client/.husky/check-staged-files.sh b/app/client/.husky/check-staged-files.sh index 1c149d4b84..07076b46fc 100644 --- a/app/client/.husky/check-staged-files.sh +++ b/app/client/.husky/check-staged-files.sh @@ -3,8 +3,13 @@ is_server_change=$(git diff --cached --name-only | grep -c "app/server") is_client_change=$(git diff --cached --name-only | grep -c "app/client") -if [ "$is_server_change" -ge 1 ]; then - echo "Running Spotless check ..." +is_merge_commit=$(git rev-parse -q --verify MERGE_HEAD) + +if [ "$is_merge_commit" ]; then + echo "Skipping server and client checks for merge commit" +else + if [ "$is_server_change" -ge 1 ]; then + echo "Running Spotless check ..." pushd app/server > /dev/null if (mvn spotless:check 1> /dev/null && popd > /dev/null) then popd @@ -12,13 +17,14 @@ if [ "$is_server_change" -ge 1 ]; then echo "Spotless check failed, please run mvn spotless:apply" exit 1 fi -else - echo "Skipping server side check..." -fi + else + echo "Skipping server side check..." + fi -if [ "$is_client_change" -ge 1 ]; then - echo "Running client check ..." - npx lint-staged --cwd app/client && git-secrets --scan --untracked && git-secrets --scan -r -else - echo "Skipping client side check..." + if [ "$is_client_change" -ge 1 ]; then + echo "Running client check ..." + npx lint-staged --cwd app/client + else + echo "Skipping client side check..." + fi fi diff --git a/app/client/.lintstagedrc b/app/client/.lintstagedrc deleted file mode 100644 index 9c4c717e14..0000000000 --- a/app/client/.lintstagedrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "src/**/*.{js,ts,tsx}": ["npx eslint --fix"], - "src/**/*.{js,ts,tsx,css,md,json}": ["npx prettier --write"], - "cypress/**/*.{js,ts}": ["npx eslint --fix"], - "cypress/**/*.{js,ts,json}": ["npx prettier --write"], - "packages/**/*.{js,ts,tsx}": ["npx eslint --fix"], - "packages/**/*.{js,ts,tsx,css,mdx,json}": ["npx prettier --write"] -} diff --git a/app/client/.lintstagedrc.json b/app/client/.lintstagedrc.json new file mode 100644 index 0000000000..53c60f061f --- /dev/null +++ b/app/client/.lintstagedrc.json @@ -0,0 +1,11 @@ +{ + "src/**/*.{js,ts,tsx}": ["eslint --fix --cache"], + "src/**/*.{css,md,json}": ["prettier --write --cache"], + "cypress/**/*.{js,ts}": [ + "cd ./cypress && eslint -c .eslintrc.json --fix --cache" + ], + "cypress/**/*.json": ["prettier --write --cache"], + "packages/**/*.{js,ts,tsx}": ["eslint --fix --cache"], + "packages/**/*.{css,mdx,json}": ["prettier --write --cache"], + "*": ["git-secrets --scan --cached"] +} diff --git a/app/client/craco.common.config.js b/app/client/craco.common.config.js index 5be83f67d9..b40523125e 100644 --- a/app/client/craco.common.config.js +++ b/app/client/craco.common.config.js @@ -1,13 +1,8 @@ /* eslint-disable @typescript-eslint/no-var-requires */ const CracoAlias = require("craco-alias"); const CracoLessPlugin = require("craco-less"); -const { - DefinePlugin, - EnvironmentPlugin -} = require("webpack"); -const { - merge -} = require("webpack-merge"); +const { DefinePlugin, EnvironmentPlugin } = require("webpack"); +const { merge } = require("webpack-merge"); const CracoBabelLoader = require("craco-babel-loader"); const path = require("path"); const webpack = require("webpack"); @@ -44,25 +39,78 @@ module.exports = { }, }, module: { - rules: [{ - test: /\.m?js/, - resolve: { - fullySpecified: false, + rules: [ + { + test: /\.m?js/, + resolve: { + fullySpecified: false, + }, }, - }, ], + { + test: /\.module\.css$/, + use: [ + { + loader: "postcss-loader", + options: { + postcssOptions: { + plugins: [ + "postcss-nesting", + "postcss-import", + "postcss-at-rules-variables", + "postcss-each", + "postcss-url", + "postcss-modules-values", + [ + "cssnano", + { + preset: ["default"], + }, + ], + ], + }, + }, + }, + ], + }, + ], }, optimization: { splitChunks: { cacheGroups: { icons: { // This determines which modules are considered icons - test: (module) => {}, + test: (module) => { + const modulePath = module.resource; + if (!modulePath) return false; + + return ( + modulePath.match( + /node_modules[\\\/]remixicon-react[\\\/]/, + ) || + modulePath.endsWith(".svg.js") || + modulePath.endsWith(".svg") + ); + }, // This determines which chunk to put the icon into. // // Why have three separate cache groups for three different kinds of // icons? Purely as an optimization: not every page needs all icons, // so we can avoid loading unused icons sometimes. - name: (module) => {}, + name: (module) => { + if ( + module.resource?.match( + /node_modules[\\\/]remixicon-react[\\\/]/, + ) + ) { + return "remix-icons"; + } + + if (module.resource?.includes("blueprint")) { + return "blueprint-icons"; + } + + return "svg-icons"; + }, // This specifies that only icons from import()ed chunks should be moved chunks: "async", // This makes webpack ignore the minimum chunk size requirement @@ -93,10 +141,8 @@ module.exports = { ], }; const scopePluginIndex = webpackConfig.resolve.plugins.findIndex( - ({ - constructor - }) => - constructor && constructor.name === "ModuleScopePlugin", + ({ constructor }) => + constructor && constructor.name === "ModuleScopePlugin", ); webpackConfig.resolve.plugins.splice(scopePluginIndex, 1); return merge(webpackConfig, config); @@ -131,10 +177,10 @@ module.exports = { ], }, }, - }, }, - plugins: [{ + plugins: [ + { plugin: CracoAlias, options: { source: "tsconfig", @@ -175,9 +221,7 @@ module.exports = { // This matters for cases where `src/` and `node_modules/` both exist – // e.g., when `` is `entities`: https://github.com/appsmithorg/appsmith/pull/20964#discussion_r1124782356 plugin: { - overrideWebpackConfig: ({ - webpackConfig - }) => { + overrideWebpackConfig: ({ webpackConfig }) => { webpackConfig.resolve.modules = [ path.resolve(__dirname, "src"), ...webpackConfig.resolve.modules, diff --git a/app/client/cypress.config.ts b/app/client/cypress.config.ts index 7cd1cc0aa5..d9c93b1f95 100644 --- a/app/client/cypress.config.ts +++ b/app/client/cypress.config.ts @@ -6,8 +6,7 @@ export default defineConfig({ requestTimeout: 60000, responseTimeout: 60000, pageLoadTimeout: 60000, - videoUploadOnPasses: false, - videoCompression: false, + video: true, numTestsKeptInMemory: 5, experimentalMemoryManagement: true, reporterOptions: { diff --git a/app/client/cypress/.eslintrc.json b/app/client/cypress/.eslintrc.json index 9b907362ee..559800a3d8 100644 --- a/app/client/cypress/.eslintrc.json +++ b/app/client/cypress/.eslintrc.json @@ -1,9 +1,12 @@ { "extends": ["../.eslintrc.base.json"], + "ignorePatterns": ["locators", "fixtures"], "env": { "cypress/globals": true }, "rules": { + "@typescript-eslint/prefer-nullish-coalescing": "off", + "@typescript-eslint/strict-boolean-expressions": "off", "@typescript-eslint/no-array-constructor": "off", "@typescript-eslint/no-namespace": "off", "@typescript-eslint/no-unused-vars": "off", diff --git a/app/client/cypress/cypress-split.ts b/app/client/cypress/cypress-split.ts deleted file mode 100644 index e8b84df417..0000000000 --- a/app/client/cypress/cypress-split.ts +++ /dev/null @@ -1,187 +0,0 @@ -/* eslint-disable no-console */ -import globby from "globby"; -import minimatch from "minimatch"; -import { exec } from "child_process"; - -const fs = require("fs/promises"); - -type GetEnvOptions = { - required?: boolean; -}; - -// some default properties -const ignoreTestFiles = [ - "cypress/e2e/**/spec_utility.ts", - "cypress/e2e/GSheet/**/*", -]; - -// used to roughly determine how many tests are in a file -const testPattern = /(^|\s)(it)\(/g; - -// This function will get all the spec paths using the pattern -async function getSpecFilePaths(specPattern: any): Promise { - const files = globby.sync(specPattern, { - ignore: ignoreTestFiles, - }); - - // ignore the files that doesn't match - const ignorePatterns = [...(ignoreTestFiles || [])]; - - // a function which returns true if the file does NOT match - const doesNotMatchAllIgnoredPatterns = (file: string) => { - // using {dot: true} here so that folders with a '.' in them are matched - const MINIMATCH_OPTIONS = { dot: true, matchBase: true }; - return ignorePatterns.every((pattern) => { - return !minimatch(file, pattern, MINIMATCH_OPTIONS); - }); - }; - const filtered = files.filter(doesNotMatchAllIgnoredPatterns); - return filtered; -} - -// This function will determine the test counts in each file to sort it further -async function getTestCount(filePath: string): Promise { - const content = await fs.readFile(filePath, "utf8"); - return content.match(testPattern)?.length || 0; -} - -// Sorting the spec files as per the test count in it -async function sortSpecFilesByTestCount( - specPathsOriginal: string[], -): Promise { - const specPaths = [...specPathsOriginal]; - - const testPerSpec: Record = {}; - - for (const specPath of specPaths) { - testPerSpec[specPath] = await getTestCount(specPath); - } - - return ( - Object.entries(testPerSpec) - // Sort by the number of tests per spec file. And this will create a consistent file list/ordering so that file division proper. - .sort((a, b) => b[1] - a[1]) - .map((x) => x[0]) - ); -} - -// This function will split the specs between the runners by calculating the modulus between spec index and the totalRunners -function splitSpecs( - specs: string[], - totalRunnersCount: number, - currentRunner: number, -): string[] { - let specs_to_run = specs.filter((_, index) => { - return index % totalRunnersCount === currentRunner; - }); - return specs_to_run; -} - -// This function will finally get the specs as a comma separated string to pass the specs to the command -async function getSpecsToRun( - totalRunnersCount = 0, - currentRunner = 0, - specPattern = "cypress/e2e/**/**/*.{js,ts}", -): Promise { - { - try { - const specFilePaths = await sortSpecFilesByTestCount( - await getSpecFilePaths(specPattern), - ); - - if (!specFilePaths.length) { - throw Error("No spec files found."); - } - const specsToRun = splitSpecs( - specFilePaths, - totalRunnersCount, - currentRunner, - ); - return specsToRun.join(","); - } catch (err) { - console.error(err); - process.exit(1); - } - } -} - -// This function will help to get and convert the env variables -function getEnvNumber( - varName: string, - { required = false }: GetEnvOptions = {}, -): number { - if (required && process.env[varName] === undefined) { - throw Error(`${varName} is not set.`); - } - const value = Number(process.env[varName]); - if (isNaN(value)) { - throw Error(`${varName} is not a number.`); - } - return value; -} - -// This function will helps to check and get env variables -function getEnvValue( - varName: string, - { required = false }: GetEnvOptions = {}, -) { - if (required && process.env[varName] === undefined) { - throw Error(`${varName} is not set.`); - } - const value = process.env[varName] === undefined ? "" : process.env[varName]; - return value; -} - -// This is to fetch the env variables from CI -function getArgs() { - return { - totalRunners: getEnvNumber("TOTAL_RUNNERS", { required: true }), - thisRunner: getEnvNumber("THIS_RUNNER", { required: true }), - specsPattern: getEnvValue("CYPRESS_SPEC_PATTERN", { required: true }), - env: getEnvValue("CYPRESS_ENV", { required: false }), - configFile: getEnvValue("CYPRESS_CONFIG_FILE", { required: false }), - headless: getEnvValue("CYPRESS_HEADLESS", { required: false }), - browser: getEnvValue("CYPRESS_BROWSER", { required: false }), - }; -} - -// This will finally segregate the specs and run the command to execute cypress -(async () => { - try { - const { - browser, - configFile, - env, - headless, - specsPattern, - thisRunner, - totalRunners, - } = getArgs(); - - let command = "yarn cypress run "; - command += browser != "" ? `--browser ${browser} ` : ""; - command += configFile != "" ? `--config-file ${configFile} ` : ""; - command += env != "" ? `--env ${env} ` : ""; - command += headless == "false" ? `--headed ` : ""; - - const specs = await getSpecsToRun(totalRunners, thisRunner, specsPattern); - const final_command = `${command} --spec "${specs}"`; - const commandProcess = exec(final_command); - - // pipe output because we want to see the results of the run - if (commandProcess.stdout) { - commandProcess.stdout.pipe(process.stdout); - } - - if (commandProcess.stderr) { - commandProcess.stderr.pipe(process.stderr); - } - - commandProcess.on("exit", (code) => { - process.exit(code || 0); - }); - } catch (err) { - console.error(err); - process.exit(1); - } -})(); diff --git a/app/client/cypress/e2e/GSheet/AllAccess_Spec.ts b/app/client/cypress/e2e/GSheet/AllAccess_Spec.ts index 60e3046e1b..2b9d832712 100644 --- a/app/client/cypress/e2e/GSheet/AllAccess_Spec.ts +++ b/app/client/cypress/e2e/GSheet/AllAccess_Spec.ts @@ -6,6 +6,9 @@ import { dataSources, agHelper, entityExplorer, + table, + assertHelper, + appSettings, } from "../../support/Objects/ObjectsCore"; const workspaceName = "gsheet apps"; @@ -22,8 +25,7 @@ describe("GSheet-Functional Tests With All Access", function () { //Adding query to insert a new spreadsheet homePage.NavigateToHome(); - homePage.CreateAppInWorkspace(workspaceName); - homePage.RenameApplication(appName); + homePage.CreateAppInWorkspace(workspaceName, appName); gsheetHelper.AddNewSpreadsheetQuery( dataSourceName, spreadSheetName, @@ -173,21 +175,20 @@ describe("GSheet-Functional Tests With All Access", function () { dataSources.RunQueryNVerifyResponseViews(8); dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929"); - // Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed. // Filter by cell range and verify - // dataSources.ValidateNSelectDropdown( - // "Filter Format", - // "Where Clause", - // "Cell range", - // ); - // agHelper.EnterValue("A2:A5", { - // propFieldName: "", - // directInput: false, - // inputFieldName: "Cell range", - // }); - // dataSources.RunQuery(); - // dataSources.RunQueryNVerifyResponseViews(8); - // dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); + dataSources.ValidateNSelectDropdown( + "Filter Format", + "Where Clause", + "Cell range", + ); + agHelper.EnterValue("A2:A5", { + propFieldName: "", + directInput: false, + inputFieldName: "Cell range", + }); + dataSources.RunQuery(); + dataSources.RunQueryNVerifyResponseViews(4); + dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); }); it("5. Update a record which is not present and verify the error", () => { @@ -286,8 +287,44 @@ describe("GSheet-Functional Tests With All Access", function () { }); }); + it("8. Import an app with all access sheet", function () { + homePage.NavigateToHome(); + homePage.ImportApp("ImportAppAllAccess.json", workspaceName); + assertHelper.WaitForNetworkCall("importNewApplication").then(() => { + agHelper.Sleep(); + //Validate table is not empty! + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("ImportAppAllAccess"); + }); + + it("9. App level import of app with all access gsheet", function () { + homePage.CreateAppInWorkspace(workspaceName, "AppLevelImport"); + appSettings.OpenAppSettings(); + appSettings.GoToImport(); + agHelper.ClickButton("Import"); + homePage.ImportApp("ImportAppAllAccess.json", "", true); + cy.wait("@importNewApplication").then(() => { + agHelper.Sleep(); + agHelper.RefreshPage(); + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("AppLevelImport"); + }); + after("Delete spreadsheet and app", function () { // Delete spreadsheet and app + homePage.SearchAndOpenApp(appName); gsheetHelper.DeleteSpreadsheetQuery(dataSourceName, spreadSheetName); cy.get("@postExecute").then((interception: any) => { expect(interception.response.body.data.body.message).to.deep.equal( diff --git a/app/client/cypress/e2e/GSheet/Misc_Spec.ts b/app/client/cypress/e2e/GSheet/Misc_Spec.ts index 7ab2b2288b..3ab603fd9d 100644 --- a/app/client/cypress/e2e/GSheet/Misc_Spec.ts +++ b/app/client/cypress/e2e/GSheet/Misc_Spec.ts @@ -11,6 +11,7 @@ import { deployMode, locators, draggableWidgets, + appSettings, } from "../../support/Objects/ObjectsCore"; const workspaceName = "gsheet apps"; @@ -45,6 +46,7 @@ describe("GSheet Miscellaneous Tests", function () { JSON.stringify(GSHEET_DATA), ); cy.get("@postExecute").then((interception: any) => { + agHelper.Sleep(); expect( interception.response.body.data.body.properties.title, ).to.deep.equal(spreadSheetName); @@ -119,7 +121,7 @@ describe("GSheet Miscellaneous Tests", function () { assertHelper.AssertNetworkStatus("@getActions", 200); assertHelper.AssertNetworkStatus("@postExecute", 200); assertHelper.AssertNetworkStatus("@updateLayout", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); //deploy the app and verify the table data @@ -176,7 +178,7 @@ describe("GSheet Miscellaneous Tests", function () { assertHelper.AssertNetworkStatus("@getActions", 200); assertHelper.AssertNetworkStatus("@postExecute", 200); assertHelper.AssertNetworkStatus("@updateLayout", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); //deploy the app and verify the table data @@ -212,8 +214,62 @@ describe("GSheet Miscellaneous Tests", function () { table.WaitUntilTableLoad(); }); + it("6. Bug: 16391 - Verify placeholder texts for insert one/many queries", function () { + // Verify place holder text for Insert one query + let placeholderText = + '{\n "name": {{nameInput.text}},\n "dob": {{dobPicker.formattedDate}},\n "gender": {{genderSelect.selectedOptionValue}} \n}'; + gsheetHelper.EnterBasicQueryValues( + "Insert One", + dataSourceName, + spreadSheetName, + false, + ); + agHelper.AssertText( + dataSources._gSheetQueryPlaceholder, + "text", + placeholderText, + ); + + // Verify place holder text for Insert many query + placeholderText = + '[{\n "name": {{nameInput.text}},\n "dob": {{dobPicker.formattedDate}},\n "gender": {{genderSelect.selectedOptionValue}} \n}]'; + + gsheetHelper.EnterBasicQueryValues( + "Insert Many", + dataSourceName, + spreadSheetName, + false, + ); + agHelper.AssertText( + dataSources._gSheetQueryPlaceholder, + "text", + placeholderText, + ); + }); + + // This test is commented since we can't use Cypress to go to the Google authorization screen. We will uncomment it whenever we figure out how to do it. + // it("7. Bug#26024 App level import of gsheet app", function () { + // homePage.NavigateToHome(); + // homePage.CreateNewWorkspace("AppLevelImport"); + // homePage.CreateAppInWorkspace("AppLevelImport", "AppLevelImportCheck"); + // appSettings.OpenAppSettings(); + // appSettings.GoToImport(); + // agHelper.ClickButton("Import"); + // homePage.ImportApp("ImportAppAllAccess.json", "", true); + // cy.wait("@importNewApplication").then(() => { + // agHelper.Sleep(); + // agHelper.ClickButton("Save & Authorize"); + // }); + // cy.url().should("contain", "accounts.google.com"); + // homePage.NavigateToHome(); + // homePage.DeleteApplication("AppLevelImportCheck"); + // homePage.DeleteWorkspace("AppLevelImport"); + // }); + after("Delete spreadsheet and app", function () { // Delete spreadsheet and app + homePage.NavigateToHome(); + homePage.SearchAndOpenApp(appName); gsheetHelper.DeleteSpreadsheetQuery(dataSourceName, spreadSheetName); cy.get("@postExecute").then((interception: any) => { expect(interception.response.body.data.body.message).to.deep.equal( diff --git a/app/client/cypress/e2e/GSheet/ReadNWrite_Access_Spec.ts b/app/client/cypress/e2e/GSheet/ReadNWrite_Access_Spec.ts index a3743dea56..8d423f1641 100644 --- a/app/client/cypress/e2e/GSheet/ReadNWrite_Access_Spec.ts +++ b/app/client/cypress/e2e/GSheet/ReadNWrite_Access_Spec.ts @@ -6,6 +6,9 @@ import { dataSources, agHelper, entityExplorer, + assertHelper, + table, + appSettings, } from "../../support/Objects/ObjectsCore"; describe("GSheet-Functional Tests With Read/Write Access", function () { @@ -26,8 +29,7 @@ describe("GSheet-Functional Tests With Read/Write Access", function () { //Adding query to insert a new spreadsheet homePage.NavigateToHome(); - homePage.CreateAppInWorkspace(workspaceName); - homePage.RenameApplication(appName); + homePage.CreateAppInWorkspace(workspaceName, appName); gsheetHelper.AddNewSpreadsheetQuery( dataSourceName.readNWrite, spreadSheetName, @@ -170,21 +172,20 @@ describe("GSheet-Functional Tests With Read/Write Access", function () { dataSources.RunQuery(); dataSources.RunQueryNVerifyResponseViews(8); dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929"); - // Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed. // Filter by cell range and verify - // dataSources.ValidateNSelectDropdown( - // "Filter Format", - // "Where Clause", - // "Cell range", - // ); - // agHelper.EnterValue("A2:A5", { - // propFieldName: "", - // directInput: false, - // inputFieldName: "Cell range", - // }); - // dataSources.RunQuery(); - // dataSources.RunQueryNVerifyResponseViews(8); - // dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); + dataSources.ValidateNSelectDropdown( + "Filter Format", + "Where Clause", + "Cell range", + ); + agHelper.EnterValue("A2:A5", { + propFieldName: "", + directInput: false, + inputFieldName: "Cell range", + }); + dataSources.RunQuery(); + dataSources.RunQueryNVerifyResponseViews(4); + dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); }); it("5. Update a record which is not present and verify the error", () => { @@ -297,8 +298,44 @@ describe("GSheet-Functional Tests With Read/Write Access", function () { }); }); + it("9. Import an app with read write access sheet", function () { + homePage.NavigateToHome(); + homePage.ImportApp("ImportAppReadWriteAccess.json", workspaceName); + assertHelper.WaitForNetworkCall("importNewApplication").then(() => { + agHelper.Sleep(); + //Validate table is not empty! + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("ImportAppReadWriteAccess"); + }); + + it("10. App level import of app with read and write access gsheet", function () { + homePage.CreateAppInWorkspace(workspaceName, "AppLevelImportReadNWrite"); + appSettings.OpenAppSettings(); + appSettings.GoToImport(); + agHelper.ClickButton("Import"); + homePage.ImportApp("ImportAppReadWriteAccess.json", "", true); + cy.wait("@importNewApplication").then(() => { + agHelper.Sleep(); + agHelper.RefreshPage(); + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("AppLevelImportReadNWrite"); + }); + after("Delete spreadsheet and app", function () { // Delete spreadsheet and app + homePage.SearchAndOpenApp(appName); gsheetHelper.DeleteSpreadsheetQuery( dataSourceName.allAccess, spreadSheetName, diff --git a/app/client/cypress/e2e/GSheet/ReadOnly_Access_Spec.ts b/app/client/cypress/e2e/GSheet/ReadOnly_Access_Spec.ts index 37caa2df32..7165c5ba1f 100644 --- a/app/client/cypress/e2e/GSheet/ReadOnly_Access_Spec.ts +++ b/app/client/cypress/e2e/GSheet/ReadOnly_Access_Spec.ts @@ -6,6 +6,9 @@ import { dataSources, agHelper, entityExplorer, + assertHelper, + table, + appSettings, } from "../../support/Objects/ObjectsCore"; describe("GSheet-Functional Tests With Read Access", function () { @@ -26,8 +29,7 @@ describe("GSheet-Functional Tests With Read Access", function () { //Adding query to insert a new spreadsheet homePage.NavigateToHome(); - homePage.CreateAppInWorkspace(workspaceName); - homePage.RenameApplication(appName); + homePage.CreateAppInWorkspace(workspaceName, appName); gsheetHelper.AddNewSpreadsheetQuery( dataSourceName.allAccess, spreadSheetName, @@ -178,21 +180,20 @@ describe("GSheet-Functional Tests With Read Access", function () { dataSources.RunQuery(); dataSources.RunQueryNVerifyResponseViews(8); dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929"); - // Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed. // Filter by cell range and verify - // dataSources.ValidateNSelectDropdown( - // "Filter Format", - // "Where Clause", - // "Cell range", - // ); - // agHelper.EnterValue("A2:A5", { - // propFieldName: "", - // directInput: false, - // inputFieldName: "Cell range", - // }); - // dataSources.RunQuery(); - // dataSources.RunQueryNVerifyResponseViews(8); - // dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); + dataSources.ValidateNSelectDropdown( + "Filter Format", + "Where Clause", + "Cell range", + ); + agHelper.EnterValue("A2:A5", { + propFieldName: "", + directInput: false, + inputFieldName: "Cell range", + }); + dataSources.RunQuery(); + dataSources.RunQueryNVerifyResponseViews(4); + dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); }); it("5. Convert field to JS and verify", () => { @@ -279,8 +280,47 @@ describe("GSheet-Functional Tests With Read Access", function () { }); }); + it("8. Import an app with read only access sheet", function () { + homePage.NavigateToHome(); + homePage.ImportApp("ImportAppReadAccess.json", workspaceName); + assertHelper.WaitForNetworkCall("importNewApplication").then(() => { + agHelper.Sleep(); + //Validate table is not empty! + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("ImportAppReadAccess"); + }); + + it("9. App level import of app with read only access gsheet", function () { + homePage.CreateAppInWorkspace( + workspaceName, + "AppLevelImportReadOnlyAccess", + ); + appSettings.OpenAppSettings(); + appSettings.GoToImport(); + agHelper.ClickButton("Import"); + homePage.ImportApp("ImportAppReadAccess.json", "", true); + cy.wait("@importNewApplication").then(() => { + agHelper.Sleep(); + agHelper.RefreshPage(); + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("AppLevelImportReadOnlyAccess"); + }); + after("Delete spreadsheet and app", function () { // Delete spreadsheet and app + homePage.SearchAndOpenApp(appName); gsheetHelper.DeleteSpreadsheetQuery( dataSourceName.allAccess, spreadSheetName, diff --git a/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts b/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts index 362de01329..a2257078c1 100644 --- a/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts +++ b/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts @@ -6,6 +6,9 @@ import { dataSources, agHelper, entityExplorer, + assertHelper, + table, + appSettings, } from "../../support/Objects/ObjectsCore"; const workspaceName = "gsheet apps"; @@ -20,8 +23,7 @@ describe("GSheet-Functional Tests With Selected Access", function () { //Adding app homePage.NavigateToHome(); - homePage.CreateAppInWorkspace(workspaceName); - homePage.RenameApplication(appName); + homePage.CreateAppInWorkspace(workspaceName, appName); }); it("1. Add and verify fetch details query", () => { @@ -161,21 +163,20 @@ describe("GSheet-Functional Tests With Selected Access", function () { dataSources.RunQueryNVerifyResponseViews(8); dataSources.AssertQueryTableResponse(0, "87bbb472ef9d90dcef140a551665c929"); - // Currently commenting this until https://github.com/appsmithorg/appsmith/issues/25447 is fixed. // Filter by cell range and verify - // dataSources.ValidateNSelectDropdown( - // "Filter Format", - // "Where Clause", - // "Cell range", - // ); - // agHelper.EnterValue("A2:A5", { - // propFieldName: "", - // directInput: false, - // inputFieldName: "Cell range", - // }); - // dataSources.RunQuery(); - // dataSources.RunQueryNVerifyResponseViews(8); - // dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); + dataSources.ValidateNSelectDropdown( + "Filter Format", + "Where Clause", + "Cell range", + ); + agHelper.EnterValue("A2:A5", { + propFieldName: "", + directInput: false, + inputFieldName: "Cell range", + }); + dataSources.RunQuery(); + dataSources.RunQueryNVerifyResponseViews(4); + dataSources.AssertQueryTableResponse(0, "eac7efa5dbd3d667f26eb3d3ab504464"); }); it("5. Update a record which is not present and verify the error", () => { @@ -291,9 +292,46 @@ describe("GSheet-Functional Tests With Selected Access", function () { }); }); + it("8. Import an app with selected access sheet", function () { + homePage.NavigateToHome(); + homePage.ImportApp("ImportAppSelectedAccess.json", workspaceName); + assertHelper.WaitForNetworkCall("importNewApplication").then(() => { + agHelper.Sleep(); + //Validate table is not empty! + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("ImportAppSelectedAccess"); + }); + + it("9. App level import of app with Selected sheet access gsheet", function () { + homePage.CreateAppInWorkspace( + workspaceName, + "AppLevelImportSelectedAccess", + ); + appSettings.OpenAppSettings(); + appSettings.GoToImport(); + agHelper.ClickButton("Import"); + homePage.ImportApp("ImportAppSelectedAccess.json", "", true); + cy.wait("@importNewApplication").then(() => { + agHelper.Sleep(); + agHelper.RefreshPage(); + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("AppLevelImportSelectedAccess"); + }); + after("Delete app", function () { // Delete app - homePage.NavigateToHome(); homePage.DeleteApplication(appName); }); }); diff --git a/app/client/cypress/e2e/GSheet/WidgetBinding_AllAccess_Spec.ts b/app/client/cypress/e2e/GSheet/WidgetBinding_AllAccess_Spec.ts index ab06580b9f..efc7b798f3 100644 --- a/app/client/cypress/e2e/GSheet/WidgetBinding_AllAccess_Spec.ts +++ b/app/client/cypress/e2e/GSheet/WidgetBinding_AllAccess_Spec.ts @@ -51,6 +51,7 @@ describe("GSheet-widget binding", function () { // Adding suggested widgets and verify dataSources.AddSuggestedWidget(Widgets.Table); + agHelper.RefreshPage(); table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); }); diff --git a/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts b/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts index 1d72dbfee3..2ae27712c2 100644 --- a/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts +++ b/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts @@ -51,6 +51,7 @@ describe("GSheet-widget binding for selected sheet access", function () { // Adding suggested widgets and verify dataSources.AddSuggestedWidget(Widgets.Table); + agHelper.RefreshPage(); table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); }); diff --git a/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts b/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts index 1a592fbf36..2865314115 100644 --- a/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts +++ b/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts @@ -9,6 +9,7 @@ import { entityExplorer, locators, assertHelper, + draggableWidgets, } from "../../../support/Objects/ObjectsCore"; describe("AForce - Community Issues page validations", function () { @@ -30,12 +31,15 @@ describe("AForce - Community Issues page validations", function () { homePage.ImportApp("CommunityIssuesExport.json"); assertHelper .WaitForNetworkCall("importNewApplication") - .then((interception: any) => { + .then((response: any) => { agHelper.Sleep(); - const { isPartialImport } = interception.response.body.data; + const { isPartialImport } = response.body.data; if (isPartialImport) { // should reconnect modal - dataSources.ReconnectSingleDSNAssert("AForceDB", "PostgreSQL"); + dataSources.ReconnectSingleDSNAssert( + String.raw`AForceDB`, + "PostgreSQL", + ); homePage.AssertNCloseImport(); } else { homePage.AssertImportToast(); @@ -66,7 +70,7 @@ describe("AForce - Community Issues page validations", function () { it("2. Validate table navigation with Server Side pagination enabled with Default selected row", () => { entityExplorer.SelectEntityByName("Table1", "Widgets"); - agHelper.AssertExistingToggleState("serversidepagination", "true"); + agHelper.AssertExistingToggleState("Server side pagination", "true"); propPane .ValidatePropertyFieldValue("Default selected row", "0") @@ -139,7 +143,7 @@ describe("AForce - Community Issues page validations", function () { //propPane.EnterJSContext("Default search text", "Bug", false); propPane.TypeTextIntoField("Default search text", "Bug"); deployMode.DeployApp(); - table.AssertSearchText("Bug", 2); + table.AssertSearchText("Bug"); table.WaitUntilTableLoad(0, 0, "v2"); table.WaitUntilTableLoad(0, 0, "v2"); deployMode.NavigateBacktoEditor(); @@ -149,7 +153,7 @@ describe("AForce - Community Issues page validations", function () { propPane.TypeTextIntoField("Default search text", "Quest", true, false); deployMode.DeployApp(); - table.AssertSearchText("Quest", 2); + table.AssertSearchText("Quest"); table.WaitUntilTableLoad(0, 0, "v2"); deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(); @@ -168,42 +172,75 @@ describe("AForce - Community Issues page validations", function () { table.WaitUntilTableLoad(0, 0, "v2"); }); - it.skip("6. Validate Search table with Client Side Search enabled & disabled", () => { + it("6. Validate Search table with Client Side Search enabled & disabled & onSearchTextChanged is set", () => { entityExplorer.SelectEntityByName("Table1", "Widgets"); - agHelper.AssertExistingToggleState("clientsidesearch", "true"); + agHelper.AssertExistingToggleState("Client side search", "true"); - deployMode.DeployApp(); - table.WaitUntilTableLoad(); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 1, "v2"); - table.SearchTable("Bug", 2); - table.WaitUntilTableLoad(0, 0, "v2"); - cy.xpath(table._searchBoxCross).click(); + table.SearchTable("Best"); + table.WaitUntilTableLoad(0, 1, "v2"); + table.ResetSearch(); table.SearchTable("Quest"); - table.WaitUntilTableLoad(0, 0, "v2"); - cy.xpath(table._searchBoxCross).click(); + table.WaitUntilTableLoad(0, 1, "v2"); + table.ResetSearch(); deployMode.NavigateBacktoEditor(); - table.WaitUntilTableLoad(); + table.WaitUntilTableLoad(0, 1, "v2"); entityExplorer.SelectEntityByName("Table1", "Widgets"); propPane.TogglePropertyState("Client side search", "Off"); - deployMode.DeployApp(); - table.WaitUntilTableLoad(); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 1, "v2"); - table.SearchTable("Bug", 2); - table.WaitForTableEmpty("v2"); - cy.xpath(table._searchBoxCross).click(); + table.SearchTable("Bug"); + table.WaitUntilTableLoad(0, 1, "v2"); //Since onSearchTextChanged is set , Search is queried for Search text with Client side search On or Off + table.ResetSearch(); table.SearchTable("Quest"); - table.WaitForTableEmpty("v2"); - cy.xpath(table._searchBoxCross).click(); + table.WaitUntilTableLoad(0, 1, "v2"); + table.ResetSearch(); + //Remove onSearchTextChanged & test deployMode.NavigateBacktoEditor(); - table.WaitUntilTableLoad(0, 0, "v2"); + table.WaitUntilTableLoad(0, 1, "v2"); entityExplorer.SelectEntityByName("Table1", "Widgets"); propPane.TogglePropertyState("Client side search", "On"); + propPane.EnterJSContext("onSearchTextChanged", ""); + propPane.ToggleJSMode("onSearchTextChanged", false); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 1, "v2"); + + table.SearchTable("Xano"); + table.WaitForTableEmpty("v2"); //Since Xano is present in 2nd page & Client side search is On + table.ResetSearch(); + + table.SearchTable("SSL"); + table.WaitUntilTableLoad(0, 1, "v2"); //as 1st page has SSL entries + table.ResetSearch(); + + //if the client side search is off, and there is no text in onSearchTextChanged, we still go ahead with client side search. this is a known limitation deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); + table.WaitUntilTableLoad(0, 1, "v2"); + entityExplorer.SelectEntityByName("Table1", "Widgets"); + propPane.TogglePropertyState("Client side search", "Off"); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 1, "v2"); + + table.SearchTable("Xano"); + table.WaitForTableEmpty("v2"); //Since Xano is present in 2nd page & Client side search is Off + table.ResetSearch(); + + table.SearchTable("SSL"); + table.WaitUntilTableLoad(0, 1, "v2"); //as 1st page has SSL entries + table.ResetSearch(); + + deployMode.NavigateBacktoEditor(); }); it("7. Validate Filter table", () => { @@ -293,8 +330,8 @@ describe("AForce - Community Issues page validations", function () { agHelper.ClickButton("Confirm"); agHelper.AssertElementAbsence(locators._toastMsg); //Making sure internal api doesnt throw error agHelper.Sleep(3000); - table.SearchTable("Suggestion", 2); - table.WaitUntilTableLoad(); + table.SearchTable("Suggestion"); + table.WaitUntilTableLoad(0, 0, "v2"); table.ReadTableRowColumnData(0, 0, "v1", 4000).then((cellData) => { expect(cellData).to.be.equal("Suggestion"); @@ -311,6 +348,7 @@ describe("AForce - Community Issues page validations", function () { agHelper.Sleep(2000); table.SelectTableRow(0, 1, true, "v2"); agHelper.AssertElementVisibility(locators._widgetInDeployed("tabswidget")); + agHelper.Sleep(2000); agHelper .GetNClick(locators._inputWidgetv1InDeployed, 0, true, 0) .type("-updating title"); diff --git a/app/client/cypress/e2e/Regression/Apps/EchoApiCMS_spec.js b/app/client/cypress/e2e/Regression/Apps/EchoApiCMS_spec.js index 0c2eafa100..24a371ad5c 100644 --- a/app/client/cypress/e2e/Regression/Apps/EchoApiCMS_spec.js +++ b/app/client/cypress/e2e/Regression/Apps/EchoApiCMS_spec.js @@ -117,26 +117,23 @@ describe("Content Management System App", function () { gitSync.CreateNConnectToGit(repoName); cy.get("@gitRepoName").then((repName) => { repoName = repName; - }); - cy.latestDeployPreview(); - cy.wait(2000); - cy.xpath("//span[text()='Curt50@gmail.com']") - .should("be.visible") - .click({ force: true }); - cy.get(appPage.mailButton).closest("div").click(); - cy.xpath(appPage.sendMailText).should("be.visible"); - cy.xpath(appPage.subjectField).type("Test"); - cy.get(appPage.contentField) - .last() - .find("textarea") - .type("Task completed", { force: true }); - cy.get(appPage.confirmButton).closest("div").click({ force: true }); - cy.get(appPage.closeButton).closest("div").click({ force: true }); - deployMode.NavigateBacktoEditor(); - }); - after(() => { - //clean up - gitSync.DeleteTestGithubRepo(repoName); + cy.latestDeployPreview(); + cy.wait(2000); + cy.xpath("//span[text()='Curt50@gmail.com']") + .should("be.visible") + .click({ force: true }); + cy.get(appPage.mailButton).closest("div").click(); + cy.xpath(appPage.sendMailText).should("be.visible"); + cy.xpath(appPage.subjectField).type("Test"); + cy.get(appPage.contentField) + .last() + .find("textarea") + .type("Task completed", { force: true }); + cy.get(appPage.confirmButton).closest("div").click({ force: true }); + cy.get(appPage.closeButton).closest("div").click({ force: true }); + deployMode.NavigateBacktoEditor(); + gitSync.DeleteTestGithubRepo(repoName); + }); }); }); diff --git a/app/client/cypress/e2e/Regression/Apps/PromisesApp_spec.js b/app/client/cypress/e2e/Regression/Apps/PromisesApp_spec.js index cb01454fbb..354a9b163b 100644 --- a/app/client/cypress/e2e/Regression/Apps/PromisesApp_spec.js +++ b/app/client/cypress/e2e/Regression/Apps/PromisesApp_spec.js @@ -4,6 +4,7 @@ import { jsEditor, apiPage, dataManager, + assertHelper, } from "../../../support/Objects/ObjectsCore"; const commonlocators = require("../../../locators/commonlocators.json"); @@ -84,46 +85,38 @@ describe("JSEditor tests", function () { ); }); // move to page 2 on table widget - cy.get(commonlocators.tableNextPage).click(); + agHelper.GetNClick(commonlocators.tableNextPage); cy.get(".t--table-widget-page-input").within(() => { cy.get("input.bp3-input").should("have.value", "2"); }); - cy.wait(3000); + cy.wait(1000); + // hit audio play button and trigger actions - /* cy.openPropertyPane("audiowidget"); - cy.get(widgetsPage.autoPlay).click({ force: true }); - cy.wait("@postExecute").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, + entityExplorer.SelectEntityByName("Audio1", "Widgets"); + agHelper.GetElement("audio").then(($audio) => { + $audio[0].play(); + }); + assertHelper.AssertNetworkStatus("@postExecute"); + // verify text is visible + agHelper.AssertContains( + "Step 4: Value is Green and will default to GREEN", + "be.visible", + ".t--draggable-textwidget span", ); - cy.wait(1000) - // verify text is visible - cy.get(".t--draggable-textwidget span") - .eq(2) - .invoke("text") - .then((text) => { - expect(text).to.equal("Step 4: Value is Green and will default to Green"); - }); - cy.get(commonlocators.tableNextPage).click() - cy.get('.t--table-widget-page-input').within(()=>{ - cy.get('input.bp3-input').should('have.value', '1') - }) - cy.get(homePageLocators.toastMessage).should( - "contain", - "Success running API query", - "GREEN", - ); */ + + agHelper.GetNClick(commonlocators.tableNextPage); + agHelper.ValidateToastMessage("Success running API query"); + agHelper.ValidateToastMessage("GREEN"); + agHelper.GetElement(".t--table-widget-page-input").within(() => { + agHelper.ValidateFieldInputValue("input.bp3-input", "2"); + }); }); - //Skipping reason? to add - it.skip("2. Testing dynamic widgets display using consecutive storeValue calls", () => { + it("2. Testing dynamic widgets display using consecutive storeValue calls", () => { entityExplorer.SelectEntityByName("JSObject1", "Queries/JS"); jsEditor.SelectFunctionDropdown("clearStore"); jsEditor.RunJSObj(); - cy.wait("@postExecute") - .its("response.body.responseMeta.status") - .should("eq", 200); + entityExplorer.SelectEntityByName("Page1", "Pages"); cy.xpath("//span[text()='Clear store']").click({ force: true }); cy.get(".t--draggable-textwidget span") .eq(5) diff --git a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_2_spec.ts index 3e6657afd0..9668a80e37 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_2_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_2_spec.ts @@ -1,19 +1,16 @@ import { agHelper, + draggableWidgets, entityExplorer, - locators, propPane, } from "../../../../support/Objects/ObjectsCore"; describe("JS to non-JS mode in Action Selector", () => { before(() => { - agHelper.AddDsl("promisesBtnDsl", locators._buttonByText("Submit")); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON); }); it("1. shows fields for navigate to from js to non-js mode", () => { - entityExplorer.SelectEntityByName("Page1", "Pages"); - entityExplorer.SelectEntityByName("Button1", "Widgets"); - propPane.EnterJSContext("onClick", "{{navigateTo()}}", true, false); propPane.ToggleJSMode("onClick", false); @@ -508,7 +505,7 @@ describe("JS to non-JS mode in Action Selector", () => { propPane.ToggleJSMode("onClick"); propPane.ValidatePropertyFieldValue( "onClick", - `{{copyToClipboard('line1\\nline2\\nline3a');}}`, + `{{copyToClipboard('aline1\\nline2\\nline3');}}`, ); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_3_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_3_spec.ts index 3a012cff4b..646f4b3cad 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_3_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/ActionSelector_JsToNonJSMode_3_spec.ts @@ -251,16 +251,16 @@ describe("JS to non-JS mode in Action Selector", () => { 0, ); agHelper.GetNAssertElementText( - propPane._actionPopupTextLabel, - "Target iframe", + propPane._windowTargetDropdown, + "Window", "have.text", - 1, + 0, ); agHelper.GetNAssertElementText( propPane._actionPopupTextLabel, "Allowed origins", "have.text", - 2, + 1, ); propPane.EnterJSContext( diff --git a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts index 4e8ac274a4..618f4166c3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts @@ -15,7 +15,8 @@ describe("Post window message", () => { entityExplorer.SelectEntityByName("Button1", "Widgets"); propPane.SelectPlatformFunction("onClick", "Post message"); agHelper.EnterActionValue("Message", "After postMessage"); - agHelper.EnterActionValue("Target iframe", "Iframe1"); + agHelper.GetNClick(propPane._windowTargetDropdown); + agHelper.GetNClick(locators._dropDownValue("Iframe1"), 0, true); entityExplorer.SelectEntityByName("Iframe1", "Widgets"); propPane.UpdatePropertyFieldValue( diff --git a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts index f71ad74fb2..c299e2fb70 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts @@ -4,6 +4,7 @@ import { jsEditor, propPane, deployMode, + debuggerHelper, } from "../../../../support/Objects/ObjectsCore"; describe("storeValue Action test", () => { @@ -198,4 +199,40 @@ describe("storeValue Action test", () => { agHelper.ValidateToastMessage(JSON.stringify(TEST_OBJECT), 0); deployMode.NavigateBacktoEditor(); }); + + it("4. Bug 24882. StoreValue, removeValue and clearStore should emit platform generated logs", function () { + const jsObjectBody = `export default { + storeFns: () => { + storeValue("xyz", 123); + removeValue("xyz"); + clearStore(); + } + }`; + + jsEditor.CreateJSObject(jsObjectBody, { + paste: true, + completeReplace: true, + toRun: true, + shouldCreateNewJSObj: true, + }); + + entityExplorer.DragDropWidgetNVerify("buttonwidget", 400, 400); + entityExplorer.SelectEntityByName("Button3", "Widgets"); + propPane.UpdatePropertyFieldValue("Label", "Test store logs"); + cy.get("@jsObjName").then((jsObj: any) => { + propPane.SelectJSFunctionToExecute( + "onClick", + jsObj as string, + "storeFns", + ); + }); + agHelper.ClickButton("Test store logs"); + + debuggerHelper.ClickDebuggerIcon(); + debuggerHelper.ClickLogsTab(); + debuggerHelper.changeLogsGroup("System logs"); + debuggerHelper.DoesConsoleLogExist("storeValue('xyz', '123', true)"); + debuggerHelper.DoesConsoleLogExist("removeValue('xyz')"); + debuggerHelper.DoesConsoleLogExist("clearStore()"); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Admin_settings_spec.js b/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Admin_settings_spec.js index 640d6ffee6..7201e85f28 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Admin_settings_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Admin_settings_spec.js @@ -36,7 +36,7 @@ describe("Admin settings page", function () { cy.visit("/settings/general", { timeout: 60000 }); // non super users are redirected to home page cy.url().should("contain", "/applications"); - cy.LogOut(); + cy.LogOut(false); }); it("3. Should test that settings page is redirected to default tab", () => { @@ -62,8 +62,8 @@ describe("Admin settings page", function () { cy.url().should("contain", "/settings/authentication"); cy.get(adminsSettings.emailTab).click(); cy.url().should("contain", "/settings/email"); - cy.get(adminsSettings.googleMapsTab).click(); - cy.url().should("contain", "/settings/google-maps"); + cy.get(adminsSettings.developerSettingsTab).click(); + cy.url().should("contain", "/settings/developer-settings"); cy.get(adminsSettings.versionTab).click(); cy.url().should("contain", "/settings/version"); }, @@ -71,7 +71,7 @@ describe("Admin settings page", function () { it( "airgap", - "4. Should test that settings page tab redirects and google maps doesn't exist - airgap", + "4. Should test that settings page tab redirects and developer settings doesn't exist - airgap", () => { cy.visit("/applications", { timeout: 60000 }); if (!Cypress.env("AIRGAPPED")) { @@ -90,7 +90,7 @@ describe("Admin settings page", function () { cy.url().should("contain", "/settings/authentication"); cy.get(adminsSettings.emailTab).click(); cy.url().should("contain", "/settings/email"); - cy.get(adminsSettings.googleMapsTab).should("not.exist"); + cy.get(adminsSettings.developerSettingsTab).should("not.exist"); cy.get(adminsSettings.versionTab).click(); cy.url().should("contain", "/settings/version"); }, diff --git a/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/General_settings_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/General_settings_Spec.ts index dfa19a0f8b..07ff7cb0bf 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/General_settings_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/General_settings_Spec.ts @@ -3,9 +3,11 @@ import { adminSettings, } from "../../../../support/Objects/ObjectsCore"; import { CURRENT_REPO, REPO } from "../../../../fixtures/REPO"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; describe("Admin Settings Page - General page validations", () => { it("1. TC# 2439 Verify 'Page title' changes upon changing Instance name", () => { + featureFlagIntercept({ license_branding_enabled: true }); adminSettings.NavigateToAdminSettings(); agHelper.ClearNType(adminSettings._instanceName, "Testing Instance name"); agHelper.ClickButton("Save"); @@ -15,4 +17,12 @@ describe("Admin Settings Page - General page validations", () => { else if (CURRENT_REPO === REPO.EE) cy.title().should("eq", "Testing Instance name"); //verifying that Instance name is not changed in EE }); + it("2. TC# 2439 Verify 'Page title' does not change upon changing Instance name in free plan", () => { + featureFlagIntercept({ license_branding_enabled: false }); + adminSettings.NavigateToAdminSettings(); + agHelper.ClearNType(adminSettings._instanceName, "Testing Instance name 2"); + agHelper.ClickButton("Save"); + agHelper.ValidateToastMessage("Successfully saved"); + cy.title().should("eq", "Appsmith"); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigation_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigation_spec.ts index 393c80467a..b8016972a9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigation_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigation_spec.ts @@ -48,9 +48,9 @@ describe("General checks for app navigation", function () { homePage.ImportApp("appNavigationTestingApp.json"); assertHelper .WaitForNetworkCall("@importNewApplication") - .then((interception) => { + .then((response) => { agHelper.Sleep(); - const { isPartialImport } = interception.response.body.data; + const { isPartialImport } = response.body.data; if (isPartialImport) { homePage.AssertNCloseImport(); } else { diff --git a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/Sidebar_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/Sidebar_spec.ts index abc60b9bf5..e6e0b7cb4c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/Sidebar_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/Sidebar_spec.ts @@ -14,9 +14,9 @@ describe("Test Sidebar navigation style", function () { homePage.ImportApp("appNavigationTestingAppWithLongPageNamesAndTitle.json"); assertHelper .WaitForNetworkCall("@importNewApplication") - .then((interception) => { + .then((response) => { agHelper.Sleep(); - const { isPartialImport } = interception.response.body.data; + const { isPartialImport } = response.body.data; if (isPartialImport) { homePage.AssertNCloseImport(); } else { diff --git a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopInline_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopInline_spec.ts index 0eb5410943..9ff0e9db70 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopInline_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopInline_spec.ts @@ -15,11 +15,9 @@ describe("Test Top + Inline navigation style", function () { assertHelper .WaitForNetworkCall("@importNewApplication") - .then((interception) => { + .then((response) => { agHelper.Sleep(); - - const { isPartialImport } = interception.response.body.data; - + const { isPartialImport } = response.body.data; if (isPartialImport) { homePage.AssertNCloseImport(); } else { diff --git a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopStacked_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopStacked_spec.ts index 49d5e47dc5..1cf689aeaa 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopStacked_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/TopStacked_spec.ts @@ -14,9 +14,9 @@ describe("Test Top + Stacked navigation style", function () { homePage.ImportApp("appNavigationTestingAppWithLongPageNamesAndTitle.json"); assertHelper .WaitForNetworkCall("importNewApplication") - .then((interception: any) => { + .then((response: any) => { agHelper.Sleep(); - const { isPartialImport } = interception.response.body.data; + const { isPartialImport } = response.body.data; if (isPartialImport) { homePage.AssertNCloseImport(); } else { diff --git a/app/client/cypress/e2e/Regression/ClientSide/AssistiveBinding/assistiveBinding_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AssistiveBinding/assistiveBinding_spec.ts new file mode 100644 index 0000000000..4a001aa7e2 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/AssistiveBinding/assistiveBinding_spec.ts @@ -0,0 +1,150 @@ +import { + agHelper, + locators, + entityExplorer, + jsEditor, + propPane, + apiPage, + dataManager, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Assistive Binding", function () { + before(() => { + // Button1 + entityExplorer.DragDropWidgetNVerify("buttonwidget", 200, 200); + + // Create JSObject1 + jsEditor.CreateJSObject( + `export default { + myFun1: ()=>{ + f; + return "yes" + } + }`, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }, + ); + + // Create JSObject2 + jsEditor.CreateJSObject( + `export default { + myFun1: ()=>{ + f; + return "yes" + } + }`, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }, + ); + + // Create Api1 + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].echoApiUrl, + ); + // Create Api2 + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].echoApiUrl, + ); + }); + it("1. Shows hints without curly braces when user types in data fields", () => { + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "JS"); + // Assert that no hint shows up when length of text is less than 3 + agHelper.AssertElementAbsence(locators._hints); + propPane.TypeTextIntoField("Label", "JSo"); + // Assert that hints show up when length of text is equal to or greater than 3 + agHelper.AssertElementExist(locators._hints); + propPane.TypeTextIntoField("Label", "unknownVar"); + // Assert that no hint shows up text doesn't match any entity name within the app + agHelper.AssertElementAbsence(locators._hints); + propPane.TypeTextIntoField("Label", "API"); + // Assert that hints show up without considering capitalization + agHelper.AssertElementExist(locators._hints); + propPane.TypeTextIntoField("Label", "{"); + // Assert that hints show up when 1 curly brace is entered + agHelper.AssertElementExist(locators._hints); + }); + it("2. Selects correct value when hint is selected", () => { + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "JSo"); + agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1"); + // After selecting "JSObject1.myFun1", expect "{{JSObject1.myFun1.data}}" in binding + propPane.ValidatePropertyFieldValue("Label", "{{JSObject1.myFun1.data}}"); + propPane.TypeTextIntoField("Label", "Api"); + agHelper.GetNClickByContains(locators._hints, "Api1"); + // After selecting "Api1", expect "{{Api1.data}}" in binding + propPane.ValidatePropertyFieldValue("Label", "{{Api1.data}}"); + }); + it("3. Shows hints after every white space", () => { + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "JSo JSo"); + // Assert that hints show up when length of text after any previous blank space is equal to or greater than 3 + agHelper.AssertElementExist(locators._hints); + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "JSo tab\tJSo"); + // Assert that hints show up when length of text after any previous tab is equal to or greater than 3 + agHelper.AssertElementExist(locators._hints); + propPane.TypeTextIntoField("Label", "JSo \nJSo"); + // Assert that hints show up when length of text after any previous new line is equal to or greater than 3 + agHelper.AssertElementExist(locators._hints); + }); + + it("4. Selects correct value and inserts in right place when hint is selected after whitespace ", () => { + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "JSo JSo"); + agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1"); + // After selecting "JSObject1.myFun1", expect "JSo {{JSObject1.myFun1.data}}" in binding + propPane.ValidatePropertyFieldValue( + "Label", + "JSo {{JSObject1.myFun1.data}}", + ); + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "JSo tab\tJSo"); + agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1"); + // After selecting "JSObject1.myFun1", expect "JSo tab {{JSObject1.myFun1.data}}" in binding + propPane.ValidatePropertyFieldValue( + "Label", + "JSo tab {{JSObject1.myFun1.data}}", + ); + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", `JSo \nJSo`); + agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1"); + // After selecting "JSObject1.myFun1", expect `JSo \n{{JSObject1.myFun1.data}}` in binding + propPane.ValidatePropertyFieldValue( + "Label", + `JSo {{JSObject1.myFun1.data}}`, + ); + }); + + it("5. Partial binding {} syntax is replaced with correct values ", () => { + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "{"); + agHelper.GetNClickByContains(locators._hints, "JSObject1.myFun1"); + // After selecting "JSObject1.myFun1", expect "{{JSObject1.myFun1.data}}" in binding + propPane.ValidatePropertyFieldValue("Label", "{{JSObject1.myFun1.data}}"); + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TypeTextIntoField("Label", "{"); + agHelper.GetNClickByContains(locators._hints, "Add a binding"); + // After selecting "Add a binding", expect "{{}}" in binding + propPane.ValidatePropertyFieldValue("Label", "{{}}"); + }); + + it("6. Works correctly when user toggles JS", () => { + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.ToggleJSMode("onClick"); + propPane.ValidatePropertyFieldValue("onClick", "{{}}"); + propPane.TypeTextIntoField("onClick", "hello", false); + // This asserts that cursor was originally between the curly braces after the user switched to js mode + propPane.ValidatePropertyFieldValue("onClick", "{{hello}}"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/Autocomplete_setters_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/Autocomplete_setters_spec.ts index a3826f622b..2f23daf1c4 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/Autocomplete_setters_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/Autocomplete_setters_spec.ts @@ -40,22 +40,22 @@ describe("Autocomplete tests for setters", () => { agHelper.GetElementsNAssertTextPresence( locators._hints, - "Button1.setColor()", + "Button1.setColor", ); agHelper.GetElementsNAssertTextPresence( locators._hints, - "Button1.setDisabled()", + "Button1.setDisabled", ); agHelper.GetElementsNAssertTextPresence( locators._hints, - "Button1.setVisibility()", + "Button1.setVisibility", ); agHelper.RemoveCharsNType(locators._codeMirrorTextArea, 7, "Input1.set"); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue()"); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()"); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility()"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility"); agHelper.RemoveCharsNType( locators._codeMirrorTextArea, @@ -63,14 +63,14 @@ describe("Autocomplete tests for setters", () => { "Checkbox1.set", ); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue()"); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()"); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility()"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setValue"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setVisibility"); agHelper.RemoveCharsNType(locators._codeMirrorTextArea, 13, "Switch1.set"); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()"); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setRequired()"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setRequired"); agHelper.Sleep(); //a bit for time for CI }); @@ -78,6 +78,6 @@ describe("Autocomplete tests for setters", () => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2, 500, 500); entityExplorer.SelectEntityByName("Button1"); propPane.EnterJSContext("onClick", "{{Input1.set", true, false); - agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled"); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts index 0a46d4af68..73a39e4106 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts @@ -130,22 +130,22 @@ describe("Autocomplete tests", () => { // eval function verification { type: "eval", - expected: "eval()", + expected: "eval", haveOrNotHave: false, }, { type: "Blob", - expected: "Blob()", + expected: "Blob", haveOrNotHave: true, }, { type: "FormData", - expected: "FormData()", + expected: "FormData", haveOrNotHave: true, }, { type: "FileReader", - expected: "FileReader()", + expected: "FileReader", haveOrNotHave: true, }, ]; @@ -167,7 +167,7 @@ describe("Autocomplete tests", () => { agHelper.GetNClick(jsEditor._lineinJsEditor(5)); agHelper.TypeText(locators._codeMirrorTextArea, "this."); - ["myFun2()", "myVar1", "myVar2"].forEach((element, index) => { + ["myFun2", "myVar1", "myVar2"].forEach((element, index) => { agHelper.AssertContains(element); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC2_spec.ts index 23a1c1b117..2b9839205c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC2_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC2_spec.ts @@ -49,7 +49,7 @@ describe("Autocomplete tests", () => { 0, ); - agHelper.GetNAssertElementText(locators._hints, "myFun1()", "have.text", 4); + agHelper.GetNAssertElementText(locators._hints, "myFun1", "have.text", 4); // Same check in JSObject1 entityExplorer.SelectEntityByName("JSObject1", "Queries/JS"); @@ -65,7 +65,7 @@ describe("Autocomplete tests", () => { 0, ); - agHelper.GetNAssertElementText(locators._hints, "myFun1()", "have.text", 4); + agHelper.GetNAssertElementText(locators._hints, "myFun1", "have.text", 4); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "JSObject1", action: "Delete", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSuggestion_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSuggestion_spec.ts index fb1cb6ecc8..ff037f1084 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSuggestion_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSuggestion_spec.ts @@ -16,8 +16,8 @@ describe("Property Pane Suggestions", () => { entityExplorer.SelectEntityByName("Button1", "Widgets"); propPane.TypeTextIntoField("Label", "/"); agHelper.Sleep(500); - agHelper.GetElementsNAssertTextPresence(locators._hints, "New binding"); - agHelper.GetNClickByContains(locators._hints, "New binding"); + agHelper.GetElementsNAssertTextPresence(locators._hints, "Add a binding"); + agHelper.GetNClickByContains(locators._hints, "Add a binding"); propPane.ValidatePropertyFieldValue("Label", "{{}}"); //typing {{}} @@ -46,6 +46,6 @@ describe("Property Pane Suggestions", () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore cy.get("body").tab(); - propPane.ValidatePropertyFieldValue("Label", "{{appsmith}}"); + propPane.ValidatePropertyFieldValue("Label", "{{JSObject1}}"); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.js index cc02c278a8..dd0150501e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.js @@ -72,7 +72,7 @@ describe("Dynamic input autocomplete", () => { cy.wait(1000); cy.evaluateErrorMessage( - "Found a reference to {{actionName}} during evaluation. Data fields cannot execute framework actions. Please remove any direct/indirect references to {{actionName}} and try again.".replaceAll( + "Please remove any direct/indirect references to {{actionName}} and try again. Data fields cannot execute framework actions.".replaceAll( "{{actionName}}", "storeValue()", ), diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/API_with_List_Widget_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/API_with_List_Widget_spec.js index 77a45a7025..a850dc28d9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/API_with_List_Widget_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/API_with_List_Widget_spec.js @@ -70,7 +70,6 @@ describe("Test Create Api and Bind to List widget", function () { it("3. Test_Validate the list widget ", function () { deployMode.NavigateBacktoEditor(); - cy.wait("@postExecute"); cy.wait("@postExecute").then((interception) => { valueToTest = JSON.stringify( interception.response.body.data.body[0].name, diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/ButtonWidgets_NavigateTo_validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/ButtonWidgets_NavigateTo_validation_spec.js index 11c1b6b8c5..83fa8a3e69 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/ButtonWidgets_NavigateTo_validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/ButtonWidgets_NavigateTo_validation_spec.js @@ -27,7 +27,7 @@ describe("Binding the button Widgets and validating NavigateTo Page functionalit deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.BUTTON)); cy.wait(2000); agHelper.ClickButton("Submit"); - cy.wait(2000); //for page to load + cy.wait(4000); //for page to load agHelper.AssertElementAbsence( locators._widgetInDeployed(draggableWidgets.BUTTON), ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_Text_WithRecaptcha_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_Text_WithRecaptcha_spec.js index a8b25d2132..faf44dab91 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_Text_WithRecaptcha_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_Text_WithRecaptcha_spec.js @@ -15,54 +15,18 @@ describe( .GetText(_.locators._widgetInCanvas("textwidget") + " span") .should("be.empty"); _.entityExplorer.SelectEntityByName("Button1"); - _.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v2"); + _.propPane.SelectPropertiesDropDown( + "Google reCAPTCHA version", + "reCAPTCHA v2", + ); _.agHelper.ClickButton("Submit"); _.agHelper .GetText(_.locators._widgetInCanvas("textwidget") + " span") .should("be.empty"); - _.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v3"); - }); - - //This test to be enabled once the product bug is fixed - it.skip("Validate the Button binding with Text Widget with Recaptcha Token with invalid key before using valid key", function () { - cy.get("button") - .contains("Submit") - .should("be.visible") - .click({ force: true }); - cy.testCodeMirrorLast(testdata.invalidKey); - _.entityExplorer.SelectEntityByName("Text1"); - - cy.get(".t--draggable-textwidget span") - .last() - .invoke("text") - .then((x) => { - cy.log(x); - expect(x).to.be.empty; - }); - _.entityExplorer.SelectEntityByName("Button1"); - - cy.get(".t--property-control-googlerecaptchaversion .bp3-popover-target") - .last() - .should("be.visible") - .click({ force: true }); - cy.get(".t--dropdown-option:contains('reCAPTCHA v2')").click({ - force: true, - }); - cy.get("button") - .contains("Submit") - .should("be.visible") - .click({ force: true }); - cy.get(".t--toast-action span").should("have.text", testdata.errorMsg); - _.entityExplorer.SelectEntityByName("Text1"); - - cy.wait(3000); - cy.get(".t--draggable-textwidget span") - .last() - .invoke("text") - .then((x) => { - cy.log(x); - expect(x).to.be.empty; - }); + _.propPane.SelectPropertiesDropDown( + "Google reCAPTCHA version", + "reCAPTCHA v3", + ); }); it("2. Validate the Button binding with Text Widget with Recaptcha Token with v2Key & upward compatibilty doesnt work", function () { @@ -77,13 +41,19 @@ describe( .GetText(_.locators._widgetInCanvas("textwidget") + " span") .should("be.empty"); _.entityExplorer.SelectEntityByName("Button1"); - _.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v2"); + _.propPane.SelectPropertiesDropDown( + "Google reCAPTCHA version", + "reCAPTCHA v2", + ); _.agHelper.ClickButton("Submit"); _.agHelper.Sleep(); _.agHelper .GetText(_.locators._widgetInCanvas("textwidget") + " span") .should("not.be.empty"); - _.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v3"); + _.propPane.SelectPropertiesDropDown( + "Google reCAPTCHA version", + "reCAPTCHA v3", + ); _.agHelper.ClickButton("Submit"); _.agHelper.Sleep(); }); @@ -94,20 +64,24 @@ describe( "Google reCAPTCHA key", testdata.v3Key, ); - _.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v3"); + _.propPane.SelectPropertiesDropDown( + "Google reCAPTCHA version", + "reCAPTCHA v3", + ); _.agHelper.ClickButton("Submit"); _.agHelper.Sleep(); cy.get("body").then(($ele) => { if ( $ele.find( _.locators._specificToast( - "Google Re-Captcha token generation failed!", + "Google reCAPTCHA token generation failed!", ), ).length || $ele .find(_.locators._widgetInCanvas("textwidget") + " span") .text() == "" ) { + _.agHelper.WaitUntilAllToastsDisappear(); _.agHelper.ClickButton("Submit"); } }); @@ -115,50 +89,30 @@ describe( .GetText(_.locators._widgetInCanvas("textwidget") + " span") .should("not.be.empty"); _.entityExplorer.SelectEntityByName("Button1"); - _.agHelper.SelectDropdownList("Google reCAPTCHA version", "reCAPTCHA v2"); + _.propPane.SelectPropertiesDropDown( + "Google reCAPTCHA version", + "reCAPTCHA v2", + ); _.agHelper.ClickButton("Submit"); - _.agHelper.AssertContains("Google Re-Captcha token generation failed!"); //toast doesnt come when run in CI! + _.agHelper.AssertContains("Google reCAPTCHA token generation failed!"); }); - //This test to be enabled once the product bug is fixed - it.skip("Validate the Button binding with Text Widget with Recaptcha Token with invalid key", function () { - cy.get("button") - .contains("Submit") - .should("be.visible") - .click({ force: true }); - cy.testCodeMirrorLast(testdata.invalidKey); - _.entityExplorer.SelectEntityByName("Text1"); - - cy.get(".t--draggable-textwidget span") - .last() - .invoke("text") - .then((x) => { - cy.log(x); - expect(x).not.to.be.empty; - }); + it("4. Validate the Button binding with Text Widget with Recaptcha Token with invalid key (after using valid key)", function () { + _.propPane.DeleteWidgetFromPropertyPane("Text1"); _.entityExplorer.SelectEntityByName("Button1"); - - cy.get(".t--property-control-googlerecaptchaversion .bp3-popover-target") - .last() - .should("be.visible") - .click({ force: true }); - cy.get(".t--dropdown-option:contains('reCAPTCHA v2')").click({ - force: true, - }); - cy.get("button") - .contains("Submit") - .should("be.visible") - .click({ force: true }); - _.entityExplorer.SelectEntityByName("Text1"); - - cy.wait(3000); - cy.get(".t--draggable-textwidget span") - .last() - .invoke("text") - .then((x) => { - cy.log(x); - expect(x).not.to.be.empty; - }); + _.propPane.UpdatePropertyFieldValue( + "Google reCAPTCHA key", + testdata.invalidKey, + ); + _.agHelper.ClickButton("Submit"); //for version 3 + _.agHelper.WaitUntilToastDisappear(testdata.errorMsg); + _.entityExplorer.SelectEntityByName("Button1"); + _.propPane.SelectPropertiesDropDown( + "Google reCAPTCHA version", + "reCAPTCHA v2", + ); + _.agHelper.ClickButton("Submit"); + _.agHelper.WaitUntilToastDisappear(testdata.errorMsg); }); }, ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_with_API_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_with_API_spec.js index 1c5d3cc4fc..8af7ef16d5 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_with_API_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/Button_with_API_spec.js @@ -41,11 +41,7 @@ describe("Bind a button and Api usecase", function () { it("2. Button-Name updation & API datasource binding with button name validation", function () { _.entityExplorer.SelectEntityByName("Button1"); //changing the Button Name - cy.widgetText( - testdata.buttonName, - widgetsPage.buttonWidget, - widgetsPage.widgetNameSpan, - ); + _.propPane.RenameWidget("Button1", testdata.buttonName); //API datasource binding with button name validation _.entityExplorer.SelectEntityByName("Api1", "Queries/JS"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js index 2fe065984b..0936a24fa7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js @@ -2,6 +2,7 @@ const queryLocators = require("../../../../locators/QueryEditor.json"); const queryEditor = require("../../../../locators/QueryEditor.json"); import homePage from "../../../../locators/HomePage"; import * as _ from "../../../../support/Objects/ObjectsCore"; +import { Widgets } from "../../../../support/Pages/DataSources"; import * as _ from "../../../../support/Objects/ObjectsCore"; @@ -30,7 +31,7 @@ describe("Addwidget from Query and bind with other widgets", function () { fixture: "addWidgetTable-mock", }); cy.onlyQueryRun(); - cy.get(queryEditor.suggestedTableWidget).click(); + _.dataSources.AddSuggestedWidget(Widgets.Table); _.jsEditor.CreateJSObject("return Query1.data;"); cy.CheckAndUnfoldEntityItem("Widgets"); cy.get(".t--entity-name").contains("Table1").click({ force: true }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/MultiSelect_Button_Text_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/MultiSelect_Button_Text_spec.js index dc1a1416e0..f33c87a753 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/MultiSelect_Button_Text_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/MultiSelect_Button_Text_spec.js @@ -59,7 +59,7 @@ Object.entries(widgetsToTest).forEach(([widgetSelector, testConfig]) => { cy.updateCodeInput(PROPERTY_SELECTOR.text, testConfig.textBindingValue); cy.closePropertyPane(); - cy.get(".rc-select-selector").click({ force: true }); + agHelper.GetNClick(".rc-select-selector", 0, true); cy.wait(1000); cy.get('.rc-select-item-option:contains("Blue")').click({ force: true }); cy.wait(1000); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/Promises_1_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Binding/Promises_1_Spec.ts index 22108c12ca..11d265c304 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/Promises_1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/Promises_1_Spec.ts @@ -236,6 +236,7 @@ showAlert("Wonderful! all apis executed", "success")).catch(() => showAlert("Ple deployMode.DeployApp(); agHelper.ClickButton("Submit"); //agHelper.AssertElementLength(locator._toastMsg, 3); //Below incases of some api's failure + agHelper.WaitUntilEleAppear(locator._toastMsg); agHelper .GetElementLength(locator._toastMsg) .then(($len) => expect($len).to.be.at.least(2)); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/SelectWidget_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Binding/SelectWidget_Spec.ts index c68cecd740..669c2ac8e0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/SelectWidget_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/SelectWidget_Spec.ts @@ -43,34 +43,34 @@ describe("Validate basic binding of Input widget to Input widget", () => { }); }); - //Till bug fixed - it.skip("2. Validation of default displayed in Select widget based on row selected + Bug 12531", function () { - table.SelectTableRow(1); - agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { - expect($selectedValue).to.eq("#2"); - }); + // //Till bug fixed + // it.skip("2. Validation of default displayed in Select widget based on row selected + Bug 12531", function () { + // table.SelectTableRow(1); + // agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + // expect($selectedValue).to.eq("#2"); + // }); - table.SelectTableRow(0); - agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { - expect($selectedValue).to.eq("#1"); - }); + // table.SelectTableRow(0); + // agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + // expect($selectedValue).to.eq("#1"); + // }); - table.SelectTableRow(2); - agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { - expect($selectedValue).to.eq("Select option"); - }); + // table.SelectTableRow(2); + // agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + // expect($selectedValue).to.eq("Select option"); + // }); - //Change select value now - failing here! - agHelper.SelectDropDown("#1"); - agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { - expect($selectedValue).to.eq("#1"); - }); + // //Change select value now - failing here! + // agHelper.SelectDropDown("#1"); + // agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + // expect($selectedValue).to.eq("#1"); + // }); - table.SelectTableRow(2, 0, false); //Deselecting here! - agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { - expect($selectedValue).to.eq("Select option"); - }); - }); + // table.SelectTableRow(2, 0, false); //Deselecting here! + // agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + // expect($selectedValue).to.eq("Select option"); + // }); + // }); it("3. Verify Selecting the already selected row deselects it", () => { table.SelectTableRow(0); //select here diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableTextPagination_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableTextPagination_spec.js index 9848792758..7ceb8805f6 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableTextPagination_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableTextPagination_spec.js @@ -136,24 +136,15 @@ describe("Test Create Api and Bind to Table widget", function () { cy.executeDbQuery("Api2", "onPageChange"); }); - it.skip("5. Table-Text, Validate Server Side Pagination of Paginate with response URL", function () { + it("5. Table-Text, Validate Server Side Pagination of Paginate with response URL", function () { /**Validate Response data with Table data in Text Widget */ entityExplorer.SelectEntityByName("Table1", "Widgets"); - cy.ValidatePaginateResponseUrlData( - apiLocators.apiPaginationPrevTest, - false, - ); + cy.ValidatePaginateResponseUrlData(apiLocators.apiPaginationPrevTest); cy.get("@postExecute.all"); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE_V1)); table.WaitUntilTableLoad(0, 0); agHelper.Sleep(3000); - cy.wait("@postExecute").then((interception) => { - let valueToTest = JSON.stringify( - interception.response.body.data.body[0].name, - ); - cy.ValidatePaginationInputData(valueToTest); - }); deployMode.NavigateBacktoEditor(); cy.wait(3000); entityExplorer.SelectEntityByName("Table1", "Widgets"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js index bdc3d6f379..9546a6d7e0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js @@ -135,7 +135,7 @@ describe("Test Create Api and Bind to Table widget", function () { cy.executeDbQuery("Api2", "onPageChange"); }); - it.skip("5. Table-Text, Validate Server Side Pagination of Paginate with Response URL", function () { + it("5. Table-Text, Validate Server Side Pagination of Paginate with Response URL", function () { /**Validate Response data with Table data in Text Widget */ cy.get("body").then(($ele) => { if ($ele.find(locators._backToEditor).length) { @@ -144,20 +144,11 @@ describe("Test Create Api and Bind to Table widget", function () { }); entityExplorer.SelectEntityByName("Table1", "Widgets"); - cy.ValidatePaginateResponseUrlDataV2( - apiPageLocators.apiPaginationPrevTest, - false, - ); + cy.ValidatePaginateResponseUrlDataV2(apiPageLocators.apiPaginationPrevTest); cy.get("@postExecute.all"); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); table.WaitUntilTableLoad(0, 0, "v2"); agHelper.Sleep(3000); - cy.wait("@postExecute").then((interception) => { - let valueToTest = JSON.stringify( - interception.response.body.data.body[0].name, - ); - cy.ValidatePaginationInputDataV2(valueToTest); - }); deployMode.NavigateBacktoEditor(); entityExplorer.SelectEntityByName("Table1", "Widgets"); cy.ValidatePaginateResponseUrlDataV2( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2WithSnipingMode_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2WithSnipingMode_spec.ts deleted file mode 100644 index 2da1aaf319..0000000000 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2WithSnipingMode_spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - agHelper, - apiPage, - table, - dataManager, -} from "../../../../support/Objects/ObjectsCore"; - -import OneClickBinding from "../../../../locators/OneClickBindingLocator"; -import FirstTimeUserOnboarding from "../../../../locators/FirstTimeUserOnboarding.json"; - -describe("Test Create Api and Bind to Table widget V2", function () { - before(() => { - agHelper.AddDsl("tableV2WidgetDsl"); - }); - - it("1. Test_Add users api, execute it and go to sniping mode.", function () { - apiPage.CreateAndFillApi( - dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, - ); - apiPage.RunAPI(); - agHelper.GetNClick(FirstTimeUserOnboarding.selectWidgetBtn); - agHelper.AssertElementVisibility(FirstTimeUserOnboarding.snipingBanner); - //Click on table name controller to bind the data and exit sniping mode - agHelper.GetNClick(table._tableV2Widget); - agHelper.AssertContains( - "Api1", - "exist", - OneClickBinding.datasourceDropdownSelector, - ); - agHelper.AssertElementAbsence(FirstTimeUserOnboarding.snipingBanner); - }); -}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Property_ToggleJs_With_Binding_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Property_ToggleJs_With_Binding_spec.js index 40456ad579..f2e2b9a93f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Property_ToggleJs_With_Binding_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Property_ToggleJs_With_Binding_spec.js @@ -92,7 +92,6 @@ describe("Table Widget V2 property pane feature validation", function () { // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(1000); propPane.EnterJSContext("Text color", testdata.bindingTextColor); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS("0", "0", "color", "rgb(0, 128, 0)"); cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(255, 0, 0)"); }); @@ -104,7 +103,6 @@ describe("Table Widget V2 property pane feature validation", function () { cy.moveToStyleTab(); cy.wait(1000); propPane.EnterJSContext("Cell Background", testdata.bindingTextColor); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS( "0", "0", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Style_ToggleJS_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Style_ToggleJS_spec.js index 70e868488a..14f7c0c2ac 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Style_ToggleJS_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Style_ToggleJS_spec.js @@ -15,7 +15,6 @@ describe("Table Widget V2 property pane feature validation", function () { cy.moveToStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Text align", testdata.bindingAlign); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS("0", "0", "justify-content", "flex-start"); cy.readTableV2dataValidateCSS("1", "0", "justify-content", "flex-end"); }); @@ -36,7 +35,6 @@ describe("Table Widget V2 property pane feature validation", function () { "Vertical alignment", testdata.bindingVerticalAlig, ); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS("0", "0", "align-items", "flex-start"); cy.readTableV2dataValidateCSS("1", "0", "align-items", "flex-end"); }); @@ -45,7 +43,6 @@ describe("Table Widget V2 property pane feature validation", function () { //cy.movetoStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Text size", testdata.bindingNewSize); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS("0", "0", "font-size", "14px"); cy.readTableV2dataValidateCSS("1", "0", "font-size", "24px"); }); @@ -53,7 +50,6 @@ describe("Table Widget V2 property pane feature validation", function () { it("5. Table widget V2 toggle test for style Alignment", function () { _.agHelper.Sleep(); _.propPane.EnterJSContext("Emphasis", testdata.bindingStyle); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS("0", "0", "font-style", "normal"); cy.readTableV2dataValidateCSS("1", "0", "font-style", "italic"); }); @@ -62,7 +58,6 @@ describe("Table Widget V2 property pane feature validation", function () { cy.moveToStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Text color", testdata.bindingTextColor); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS("0", "0", "color", "rgb(0, 128, 0)"); cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(255, 0, 0)"); }); @@ -71,7 +66,6 @@ describe("Table Widget V2 property pane feature validation", function () { cy.moveToStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Cell Background", testdata.bindingTextColor); - cy.wait("@updateLayout"); cy.readTableV2dataValidateCSS( "0", "0", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableWithSnipingMode_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableWithSnipingMode_spec.js deleted file mode 100644 index 99d34acec3..0000000000 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableWithSnipingMode_spec.js +++ /dev/null @@ -1,21 +0,0 @@ -import * as _ from "../../../../support/Objects/ObjectsCore"; - -describe("Test Create Api and Bind to Table widget", function () { - before(() => { - _.agHelper.AddDsl("tableWidgetDsl"); - }); - - it("1. Test_Add users api, execute it and go to sniping mode.", function () { - cy.createAndFillApi(this.dataSet.userApi, "/mock-api?records=10"); - cy.RunAPI(); - cy.get(".t--select-in-canvas").click(); - cy.get(".t--sniping-mode-banner").should("be.visible"); - //Click on table name controller to bind the data and exit sniping mode - cy.get(".t--draggable-tablewidget").trigger("mouseover"); - cy.get(".t--settings-sniping-control").click(); - cy.get(".t--property-control-tabledata .CodeMirror").contains( - "{{Api1.data}}", - ); - cy.get(".t--sniping-mode-banner").should("not.exist"); - }); -}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/Table_Style_ToggleJS_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/Table_Style_ToggleJS_spec.js index ac38e18a95..a4f7c1af83 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/Table_Style_ToggleJS_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/Table_Style_ToggleJS_spec.js @@ -15,7 +15,6 @@ describe("Table Widget property pane feature validation", function () { //cy.movetoStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Text align", testdata.bindingAlign); - cy.wait("@updateLayout"); cy.readTabledataValidateCSS("0", "0", "justify-content", "flex-start"); cy.readTabledataValidateCSS("1", "0", "justify-content", "flex-end"); }); @@ -36,7 +35,6 @@ describe("Table Widget property pane feature validation", function () { "Vertical alignment", testdata.bindingVerticalAlig, ); - cy.wait("@updateLayout"); cy.readTabledataValidateCSS("0", "0", "align-items", "flex-start"); cy.readTabledataValidateCSS("1", "0", "align-items", "flex-end"); }); @@ -46,7 +44,6 @@ describe("Table Widget property pane feature validation", function () { _.agHelper.Sleep(); _.propPane.EnterJSContext("Text size", testdata.bindingSize); cy.wait(2000); - cy.wait("@updateLayout"); cy.readTabledataValidateCSS("0", "0", "font-size", "14px"); cy.readTabledataValidateCSS("1", "0", "font-size", "24px"); }); @@ -55,7 +52,6 @@ describe("Table Widget property pane feature validation", function () { //cy.movetoStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Font Style", testdata.bindingStyle); - cy.wait("@updateLayout"); cy.readTabledataValidateCSS("0", "0", "font-style", "normal"); cy.readTabledataValidateCSS("1", "0", "font-style", "italic"); }); @@ -64,7 +60,6 @@ describe("Table Widget property pane feature validation", function () { //cy.movetoStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Text color", testdata.bindingTextColor); - cy.wait("@updateLayout"); cy.readTabledataValidateCSS("0", "0", "color", "rgb(0, 128, 0)"); cy.readTabledataValidateCSS("1", "0", "color", "rgb(255, 0, 0)"); }); @@ -73,7 +68,6 @@ describe("Table Widget property pane feature validation", function () { //cy.movetoStyleTab(); _.agHelper.Sleep(); _.propPane.EnterJSContext("Cell Background", testdata.bindingTextColor); - cy.wait("@updateLayout"); cy.readTabledataValidateCSS( "0", "0", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/xmlParser_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/xmlParser_spec.js index 5cd7b98d3f..6adf665579 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/xmlParser_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/xmlParser_spec.js @@ -3,9 +3,21 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; describe("xml2json text", function () { before(() => { - _.agHelper.AddDsl("xmlParser"); + _.homePage.NavigateToHome(); + _.homePage.ImportApp("xmlParser.json"); + _.homePage.AssertImportToast(); }); - it("1. Publish widget and validate the data displayed in text widget from xmlParser function", function () { + + it("1. Check if XMLparser v3 autocomplete works", function () { + _.entityExplorer.SelectEntityByName("Text2", "Widgets"); + _.propPane.TypeTextIntoField("Text", "{{xmlParser.j", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "j2xParser"); + + _.propPane.TypeTextIntoField("Text", "{{new xmlParser.j2xParser().p", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "parse"); + }); + + it("2. Publish widget and validate the data displayed in text widget from xmlParser function", function () { _.deployMode.DeployApp(); cy.get(publish.textWidget) .first() diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts index bec6233437..4fb38b0c78 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts @@ -10,7 +10,8 @@ import { createMessage, } from "../../../../support/Objects/CommonErrorMessages"; -const largeResponseApiUrl = "https://api.publicapis.org/entries"; +const largeResponseApiUrl = "https://api.github.com/emojis"; +//"https://api.publicapis.org/entries"; //"https://jsonplaceholder.typicode.com/photos";//Commenting since this is faster sometimes & case is failing describe("Abort Action Execution", function () { @@ -49,7 +50,7 @@ describe("Abort Action Execution", function () { action: "Delete", entityType: entityItems.Query, }); - dataSources.DeleteDatasouceFromWinthinDS($dsName as unknown as string); + dataSources.DeleteDatasourceFromWithinDS($dsName as unknown as string); }); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts index 3c0249cfc5..07d69580e0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts @@ -280,8 +280,7 @@ function multiTreeSelectAndReset() { } function radiogroupAndReset() { - cy.get("input").last().click({ force: true }); - cy.wait(1000); + _.agHelper.GetNClick("input", 1, true, 1000); _.agHelper.GetNAssertElementText( _.locators._textWidgetInDeployed, "N", @@ -350,8 +349,7 @@ function checkboxGroupAndReset() { } function checkboxAndReset() { - cy.get("input").last().click({ force: true }); - cy.wait(1000); + _.agHelper.GetNClick("input", 0, true, 1000); _.agHelper.GetNAssertElementText( _.locators._textWidgetInDeployed, "false", diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/ApiBugs_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/ApiBugs_Spec.ts index 1c45a41a1d..a320a1c4ad 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/ApiBugs_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/ApiBugs_Spec.ts @@ -8,6 +8,8 @@ import { dataManager, propPane, table, + draggableWidgets, + entityExplorer, } from "../../../../support/Objects/ObjectsCore"; import { Widgets } from "../../../../support/Pages/DataSources"; @@ -15,16 +17,9 @@ import { ERROR_ACTION_EXECUTE_FAIL, createMessage, } from "../../../../support/Objects/CommonErrorMessages"; -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; describe("API Bugs", function () { before(() => { - featureFlagIntercept( - { - ab_ds_binding_enabled: false, - }, - false, - ); agHelper.RefreshPage(); }); @@ -93,4 +88,42 @@ describe("API Bugs", function () { value: "4{{Math.random() > 0.5 ? '¶m1=5' : '¶m2=6'}}", }); }); + + it("5. Bug 26897, Invalid binding of table data when used existing suggested widgets for an action returning object & array", function () { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE); + entityExplorer.NavigateToSwitcher("Explorer"); + + // Case where api returns array response + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, + "ARRAY_RESPONSE", + ); + apiPage.RunAPI(); + dataSources.AddSuggestedWidget( + Widgets.Table, + dataSources._addSuggestedExisting, + ); + debuggerHelper.AssertErrorCount(0); + table.WaitUntilTableLoad(0, 0, "v2"); + propPane.AssertPropertiesDropDownCurrentValue( + "Table data", + "ARRAY_RESPONSE", + ); + + // Create API so that it returns object response + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiObjectUrl, + "OBJECT_RESPONSE", + ); + apiPage.RunAPI(); + dataSources.AddSuggestedWidget( + Widgets.Table, + dataSources._addSuggestedExisting, + ); + table.WaitUntilTableLoad(0, 0, "v2"); + propPane.ValidatePropertyFieldValue( + "Table data", + "{{OBJECT_RESPONSE.data.users}}", + ); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug18035_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug18035_Spec.ts index 453518f616..b2b461aafa 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug18035_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug18035_Spec.ts @@ -12,7 +12,7 @@ describe( dataSources.CreatePlugIn("Google Sheets"); agHelper.GoBack(); agHelper.AssertContains( - "Save and authorize", + "Save & Authorize", "exist", dataSources._datasourceModalSave, ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug19933_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug19933_spec.ts deleted file mode 100644 index 277debe0ba..0000000000 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug19933_spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { agHelper, dataSources } from "../../../../support/Objects/ObjectsCore"; - -let dsName: string; - -const testString = "test"; - -describe("Bug 19933: Authenticated API DS in case of OAuth2, should have save and authorise button enabled all the times", function () { - it("1. Create Auth API DS, save i, now edit again and check the save and authorise button state", function () { - dataSources.NavigateToDSCreateNew(); - agHelper.GenerateUUID(); - cy.get("@guid").then((uid) => { - dsName = "AuthAPI " + uid; - dataSources.CreatePlugIn("Authenticated API"); - agHelper.RenameWithInPane(dsName, false); - dataSources.FillAuthAPIUrl(); - dataSources.AddOAuth2AuthorizationCodeDetails( - testString, - testString, - testString, - testString, - ); - dataSources.SaveDatasource(); - }); - - dataSources.EditDatasource(); - agHelper.AssertElementEnabledDisabled( - dataSources._saveAndAuthorizeDS, - 0, - false, - ); - dataSources.DeleteDSDirectly(); - }); -}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug24486_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug24486_Spec.ts index 5c244fb596..e82e0417f2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug24486_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug24486_Spec.ts @@ -1,10 +1,10 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; -let guid; +let guid: any; let ws1Name; let ws2Name; -let app1Name; -let repoName; +let app1Name: any; +let repoName: any; let branchName; describe("Issue 24486 - Issue with Export Application", () => { @@ -19,7 +19,7 @@ describe("Issue 24486 - Issue with Export Application", () => { }); }); - it("Should export the current branch", () => { + it("1. Should export the current branch", () => { _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.BUTTON, 200, 200); _.gitSync.CreateNConnectToGit(); cy.get("@gitRepoName").then((repName) => { @@ -60,7 +60,7 @@ describe("Issue 24486 - Issue with Export Application", () => { }); }); - it("Should import the exported branch", () => { + it("2. Should import the exported branch", () => { ws2Name = "Bug24486-w2" + guid; _.homePage.CreateNewWorkspace(ws2Name, true); _.homePage.ImportApp("app-b24486.json", ws2Name); @@ -73,7 +73,7 @@ describe("Issue 24486 - Issue with Export Application", () => { _.propPane.ValidatePropertyFieldValue("Label", "Submit"); }); - // after(() => { - // _.gitSync.DeleteTestGithubRepo(repoName); - // }); + after(() => { + _.gitSync.DeleteTestGithubRepo(repoName); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug25894_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug25894_spec.ts index 56521756c5..ab630a5e0a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug25894_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug25894_spec.ts @@ -1,24 +1,38 @@ -import * as _ from "../../../../support/Objects/ObjectsCore"; - -const { entityExplorer, propPane } = _; +import { + entityExplorer, + propPane, + draggableWidgets, + agHelper, +} from "../../../../support/Objects/ObjectsCore"; describe("Bug 25894 - Moustache brackets should be highlighted", () => { it("1. should show {{ }} in bold", () => { - entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.BUTTON, 200, 200); - + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON); entityExplorer.SelectEntityByName("Button1", "Widgets"); propPane.EnterJSContext( "onClick", - `{{Api1.run({ + `{{ Api1.run({ "key": Button1.text }).then(() => { storeValue('my-secret-key', Button3.text); Query1.run(); }).catch(() => {});const a = { a: "key"} }}`, ); + agHelper + .GetElement("span") + .filter((index, element) => { + const text = Cypress.$(element).text(); + return text.includes("{{") || text.includes("{"); + }) + .should("have.class", "cm-binding-brackets"); - cy.get("span").contains("{{").should("have.class", "cm-binding-brackets"); - cy.get("span").contains("}}").should("have.class", "cm-binding-brackets"); + agHelper + .GetElement("span") + .filter((index, element) => { + const text = Cypress.$(element).text(); + return text.includes("}}") || text.includes("}"); + }) + .should("have.class", "cm-binding-brackets"); // Check the class of filtered elements }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26126_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26126_spec.ts new file mode 100644 index 0000000000..4b5ba6c883 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26126_spec.ts @@ -0,0 +1,26 @@ +import { + dataSources, + entityExplorer, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Bug 26126: Fix DS button disability", function () { + it("ensures save button is correctly updated when DS required fields change", function () { + dataSources.NavigateToDSCreateNew(); + dataSources.CreatePlugIn("S3"); + dataSources.FillS3DSForm(); + dataSources.AssertSaveDSButtonDisability(false); + dataSources.ValidateNSelectDropdown( + "S3 service provider", + "Amazon S3", + "Upcloud", + ); + dataSources.AssertSaveDSButtonDisability(true); + dataSources.ValidateNSelectDropdown( + "S3 service provider", + "Upcloud", + "Amazon S3", + ); + + dataSources.AssertSaveDSButtonDisability(false); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26716_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26716_Spec.ts new file mode 100644 index 0000000000..88c20a7c80 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26716_Spec.ts @@ -0,0 +1,72 @@ +import { + agHelper, + dataSources, + entityExplorer, +} from "../../../../support/Objects/ObjectsCore"; +let dsName: any, userMock: string, movieMock: string; + +describe( + "excludeForAirgap", + "Bug 26716: Datasource selected from entity explorer should be correctly highlighted", + function () { + it("1. Create users and movies mock datasources and switch between them through entity explorer, check the active state", function () { + dataSources.CreateMockDB("Users").then((mockDBName) => { + userMock = mockDBName; + cy.log("Mock DB Name: " + userMock); + dataSources.CreateQueryAfterDSSaved(); //create dummy query for DS to be visible in entity explorer + dataSources.CreateMockDB("Movies").then((mockDBName) => { + movieMock = mockDBName; + cy.log("Mock DB Name: " + mockDBName); + dataSources.CreateQueryAfterDSSaved(); //create dummy query for DS to be visible in entity explorer + dataSources.CreateDataSource("Postgres"); + dataSources.CreateQueryAfterDSSaved(); //create dummy query for DS to be visible in entity explorer + cy.get("@dsName").then(($dsName) => { + dsName = $dsName; + // Select Users + entityExplorer.SelectEntityByName(userMock, "Datasources"); + agHelper.Sleep(200); + agHelper.AssertClassExists( + dataSources._entityExplorerID(userMock), + "active", + ); + + // Switch to Movies + entityExplorer.SelectEntityByName(movieMock, "Datasources"); + agHelper.Sleep(200); + agHelper.AssertClassExists( + dataSources._entityExplorerID(movieMock), + "active", + ); + + // Switch to custom DS + entityExplorer.SelectEntityByName(dsName, "Datasources"); + entityExplorer.ExpandCollapseEntity(dsName, false); + agHelper.Sleep(200); + agHelper.AssertClassExists( + dataSources._entityExplorerID(dsName), + "active", + ); + + // Delete all datasources + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Query1", + action: "Delete", + }); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Query2", + action: "Delete", + }); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Query3", + action: "Delete", + }); + + dataSources.DeleteDatasouceFromActiveTab(userMock); + dataSources.DeleteDatasouceFromActiveTab(movieMock); + dataSources.DeleteDatasouceFromActiveTab(dsName); + }); + }); + }); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26941_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26941_Spec.ts new file mode 100644 index 0000000000..a92a69d0d7 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26941_Spec.ts @@ -0,0 +1,45 @@ +import { + agHelper, + apiPage, + dataManager, + debuggerHelper, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Inconsistent Api error after the invalid chars are removed from header key", function () { + it("1. Checking whether the appropriate error is displayed even after the removal of invalid chars in header key.", function () { + const randomApi = `${ + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl + }123`; + apiPage.CreateAndFillApi(randomApi); + apiPage.RunAPI(false, 20, { + expectedPath: "response.body.data.body.data.isExecutionSuccess", + expectedRes: false, + }); + + agHelper.AssertElementAbsence( + debuggerHelper.locators._debuggerDownStreamErrMsg, + ); + + apiPage.EnterHeader(">", ""); + apiPage.RunAPI(false, 20, { + expectedPath: "response.body.data.body.data.isExecutionSuccess", + expectedRes: false, + }); + + cy.get("@postExecute").then((interception: any) => { + debuggerHelper.AssertDownStreamLogError( + interception.response.body.data.pluginErrorDetails + .downstreamErrorMessage, + ); + }); + + apiPage.EnterHeader("", ""); + apiPage.RunAPI(false, 20, { + expectedPath: "response.body.data.body.data.isExecutionSuccess", + expectedRes: false, + }); + agHelper.AssertElementAbsence( + debuggerHelper.locators._debuggerDownStreamErrMsg, + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug27817_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug27817_Spec.ts new file mode 100644 index 0000000000..deb6dd0f35 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug27817_Spec.ts @@ -0,0 +1,25 @@ +import { + agHelper, + assertHelper, + dataSources, +} from "../../../../support/Objects/ObjectsCore"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; + +describe("Datasource structure schema preview data", () => { + before(() => { + featureFlagIntercept({ ab_gsheet_schema_enabled: true }); + dataSources.CreateDataSource("Postgres"); + }); + + it("1. Table selection should be enabled and add template button absent", () => { + dataSources.selectTabOnDatasourcePage("View data"); + agHelper.TypeText(dataSources._datasourceStructureSearchInput, "users"); + agHelper.GetNClick( + dataSources._dsPageTabContainerTableName("public.users"), + ); + assertHelper.AssertNetworkExecutionSuccess("@schemaPreview"); + agHelper.AssertElementAbsence( + dataSources._dsPageTableTriggermenuTarget("public.users"), + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug28287_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug28287_Spec.ts new file mode 100644 index 0000000000..fd743c5a70 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug28287_Spec.ts @@ -0,0 +1,44 @@ +import { + dataSources, + agHelper, + entityExplorer, + propPane, + debuggerHelper, + draggableWidgets, +} from "../../../../support/Objects/ObjectsCore"; + +let dsName: any; +let queryName: string; + +describe("Bug 28287: Binding query to widget, check query response in query editor on page load", function () { + before("Drag drop a text widget", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT); + }); + + it("1. Check query response in query editor on page load", () => { + agHelper.GenerateUUID(); + cy.get("@guid").then((uuid) => { + dataSources.CreateDataSource("Postgres"); + cy.get("@dsName").then(($dsName) => { + dsName = $dsName; + }); + queryName = `Query_${uuid}`; + dataSources.CreateQueryAfterDSSaved( + "SELECT * FROM users LIMIT 10", + queryName, + ); + dataSources.ToggleUsePreparedStatement(false); + + entityExplorer.SelectEntityByName("Text1"); + propPane.TypeTextIntoField("Text", `{{${queryName}.data}}`); + + agHelper.RefreshPage(); + + agHelper.Sleep(1000); + + entityExplorer.SelectEntityByName(queryName, "Queries/JS"); + + agHelper.AssertElementVisibility(dataSources._queryResponse("TABLE")); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug9334_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug9334_Spec.ts index 22a6168845..540d3eb044 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug9334_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug9334_Spec.ts @@ -34,7 +34,7 @@ describe("Bug 9334: The Select widget value is sent as null when user switches b agHelper.AssertContains("Successfully generated a page"); //assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); table.WaitUntilTableLoad(); @@ -52,10 +52,11 @@ describe("Bug 9334: The Select widget value is sent as null when user switches b agHelper.AssertContains("Successfully generated a page"); //assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); table.WaitUntilTableLoad(); }); + it("2. Navigate & Assert toast", () => { //Navigating between CRUD (Page3) & EmptyPage (Page2): entityExplorer.SelectEntityByName("Page1"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bugs26410_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bugs26410_spec.ts new file mode 100644 index 0000000000..6db6c260ce --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bugs26410_spec.ts @@ -0,0 +1,30 @@ +import { + dataSources, + entityExplorer, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Fix UQI query switching", function () { + it( + "excludeForAirgap", + "1. The command of the Mongo query must be preserved and should not default to initial value after changed.", + function () { + dataSources.NavigateToDSCreateNew(); + dataSources.CreateDataSource("Mongo", false, false); + dataSources.CreateQueryAfterDSSaved("", "MongoQuery"); + dataSources.ValidateNSelectDropdown( + "Commands", + "Find document(s)", + "Insert document(s)", + ); + dataSources.NavigateToDSCreateNew(); + dataSources.CreateDataSource("Twilio", false, false); + dataSources.CreateQueryAfterDSSaved("", "TwilioQuery"); + dataSources.ValidateNSelectDropdown("Commands", "", "Schedule message"); + entityExplorer.SelectEntityByName("MongoQuery", "Queries/JS"); + dataSources.ValidateNSelectDropdown("Commands", "Insert document(s)"); + + entityExplorer.SelectEntityByName("TwilioQuery", "Queries/JS"); + dataSources.ValidateNSelectDropdown("Commands", "Schedule message"); + }, + ); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/DSDiscardBugs_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/DSDiscardBugs_spec.ts index b7aa9c4eb8..c02e3abdd2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/DSDiscardBugs_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/DSDiscardBugs_spec.ts @@ -44,25 +44,6 @@ describe("datasource unsaved changes popup shows even without changes", function _.dataSources.EditDatasource(); _.agHelper.GoBack(); _.agHelper.AssertElementVisibility(_.dataSources._activeDS); - - // Edit DS from active tab and add oauth2 details - _.dataSources.EditDSFromActiveTab(dsName); - _.dataSources.AddOAuth2AuthorizationCodeDetails( - testString, - testString, - testString, - testString, - ); - _.dataSources.UpdateDatasource(); - _.agHelper.Sleep(); - - // Now edit DS, and ensure that discard popup is not shown on back button click - // Even if custom authentication params are being initialized, we shouldnt see the popup - // as those are not initialized by user - _.dataSources.EditDatasource(); - _.agHelper.GoBack(); - _.agHelper.AssertElementVisibility(_.dataSources._activeDS); - _.dataSources.DeleteDatasouceFromActiveTab(dsName); }); }); @@ -154,7 +135,7 @@ describe("datasource unsaved changes popup shows even without changes", function // Edit datasource, change connection string uri param and click on back button _.dataSources.EditDatasource(); - _.agHelper.UpdateInputValue(_.dataSources._host, "jargons"); + _.agHelper.UpdateInputValue(_.dataSources._host(), "jargons"); // Assert that popup is visible _.dataSources.cancelDSEditAndAssertModalPopUp(true, false); @@ -164,7 +145,7 @@ describe("datasource unsaved changes popup shows even without changes", function // validate the input field value still remains as the saved value _.agHelper.ValidateFieldInputValue( - _.dataSources._host, + _.dataSources._host(), _.dataManager.dsValues.Staging.mongo_host, ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/DatasourceSchema_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/DatasourceSchema_spec.ts index f43787fca4..7b8e8cf46d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/DatasourceSchema_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/DatasourceSchema_spec.ts @@ -1,4 +1,3 @@ -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import { agHelper, entityItems, @@ -53,26 +52,23 @@ describe("Datasource form related tests", function () { action: "Delete", entityType: entityItems.Query, }); - dataSources.DeleteDatasouceFromWinthinDS(dataSourceName); + dataSources.DeleteDatasourceFromWithinDS(dataSourceName); }); it( "excludeForAirgap", "3. Verify if schema (table and column) exist in query editor and searching works", () => { - featureFlagIntercept( - { - ab_ds_schema_enabled: true, - }, - false, - ); agHelper.RefreshPage(); dataSources.CreateMockDB("Users"); dataSources.CreateQueryAfterDSSaved(); dataSources.VerifyTableSchemaOnQueryEditor("public.users"); entityExplorer.ExpandCollapseEntity("public.users"); dataSources.VerifyColumnSchemaOnQueryEditor("id"); - dataSources.FilterAndVerifyDatasourceSchemaBySearch("gender", "column"); + dataSources.FilterAndVerifyDatasourceSchemaBySearch( + "public.us", + "public.users", + ); }, ); @@ -80,12 +76,6 @@ describe("Datasource form related tests", function () { "excludeForAirgap", "4. Verify if collapsible opens when refresh button is opened.", () => { - featureFlagIntercept( - { - ab_ds_schema_enabled: true, - }, - false, - ); agHelper.RefreshPage(); dataSources.CreateMockDB("Users"); dataSources.CreateQueryAfterDSSaved(); @@ -100,12 +90,6 @@ describe("Datasource form related tests", function () { // the full list for schema-less plugins can be found here. https://www.notion.so/appsmith/Don-t-show-schema-section-for-plugins-that-don-t-support-it-78f82b6abf7948c5a7d596ae583ed8a4?pvs=4#3862343ca2564f7e83a2c8279965ca61 it("5. Verify schema does not show up in schema-less plugins", () => { - featureFlagIntercept( - { - ab_ds_schema_enabled: true, - }, - false, - ); agHelper.RefreshPage(); dataSources.CreateDataSource("Redis", true, false); dataSources.CreateQueryAfterDSSaved(); @@ -113,18 +97,9 @@ describe("Datasource form related tests", function () { }); it("6. Verify schema searching works for datasources with empty columns for example S3.", () => { - featureFlagIntercept( - { - ab_ds_schema_enabled: true, - }, - false, - ); agHelper.RefreshPage(); dataSources.CreateDataSource("S3", true, false); dataSources.CreateQueryAfterDSSaved(); - dataSources.FilterAndVerifyDatasourceSchemaBySearch( - "appsmith-hris", - "table", - ); + dataSources.FilterAndVerifyDatasourceSchemaBySearch("appsmith-hris"); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/GitBugs_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/GitBugs_Spec.ts index 71357db067..6234eb0e30 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/GitBugs_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/GitBugs_Spec.ts @@ -46,6 +46,7 @@ describe("Git Bugs", function () { }); }); }); + it("3. Bug 18376: navigateTo fails to set queryParams if the app is connected to Git", () => { _.entityExplorer.AddNewPage(); _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT); @@ -143,6 +144,7 @@ describe("Git Bugs", function () { }); it("7. Bug 24920: Not able to discard app settings changes for the first time in git connected app ", function () { + _.gitSync.SwitchGitBranch("master", false, true); // add navigation settings changes _.agHelper.GetNClick(_.appSettings.locators._appSettings); _.agHelper.GetNClick(_.appSettings.locators._navigationSettingsTab); @@ -173,6 +175,7 @@ describe("Git Bugs", function () { _.agHelper.GetNClick(_.gitSync._dropdownmenu, 5); _.gitSync.CloseGitSyncModal(); }); + it("9. Bug 24206 : Open repository button is not functional in git sync modal", function () { _.gitSync.SwitchGitBranch("master"); _.appSettings.OpenPaneAndChangeTheme("Moon"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/InputTruncateCheck_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/InputTruncateCheck_Spec.ts index 3e61f85608..4275682fde 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/InputTruncateCheck_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/InputTruncateCheck_Spec.ts @@ -93,7 +93,7 @@ Object.entries(widgetsToTest).forEach(([widgetSelector, testConfig], index) => { if (index === 0) { configureApi(); } - // entityExplorer.PinUnpinEntityExplorer(false); + entityExplorer.PinUnpinEntityExplorer(false); entityExplorer.DragDropWidgetNVerify(widgetSelector, 300, 200); entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 400, 400); //entityExplorer.SelectEntityByName(draggableWidgets.BUTTONNAME("1")); @@ -110,7 +110,7 @@ Object.entries(widgetsToTest).forEach(([widgetSelector, testConfig], index) => { PROPERTY_SELECTOR.TextFieldName, `{{appsmith.store.textPayloadOnSubmit}}`, ); - // entityExplorer.PinUnpinEntityExplorer(true); + entityExplorer.PinUnpinEntityExplorer(true); }); it("2. StoreValue should have complete input value", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Moment_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Moment_Spec.ts index 5f08a6cb8b..57c3edc845 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Moment_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Moment_Spec.ts @@ -37,6 +37,7 @@ describe("Bug #14299 - The data from the query does not show up on the widget", completeReplace: true, toRun: false, shouldCreateNewJSObj: true, + prettify: false, }, ); @@ -109,8 +110,7 @@ describe("Bug #14299 - The data from the query does not show up on the widget", after( "Verify Deletion of the datasource after all created queries are deleted", () => { - deployMode.NavigateBacktoEditor(); - agHelper.AssertContains("ran successfully"); //runAstros triggered on PageLaoad of Edit page! + deployMode.NavigateBacktoEditor("ran successfully"); //runAstros triggered on PageLaoad of Edit page! entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "JSObject1", @@ -122,7 +122,7 @@ describe("Bug #14299 - The data from the query does not show up on the widget", deployMode.DeployApp(locators._widgetInDeployed("tablewidget"), false); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Datasources"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }, ); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/CommunityTemplate/PublishCommunityTemplatesFlow_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/CommunityTemplate/PublishCommunityTemplatesFlow_spec.ts new file mode 100644 index 0000000000..34d52d73ba --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/CommunityTemplate/PublishCommunityTemplatesFlow_spec.ts @@ -0,0 +1,111 @@ +import { + agHelper, + communityTemplates, + inviteModal, + locators, +} from "../../../../support/Objects/ObjectsCore"; + +const communityForm = communityTemplates.locators._communityForm; +describe("excludeForAirgap", "Publish app to Community flow", () => { + afterEach(() => { + agHelper.RefreshPage(); + }); + + beforeEach(() => { + agHelper.GetNClick(inviteModal.locators._shareButton); + agHelper.GetNClick(inviteModal.locators._publishTab); + }); + + function prepareTemplateFormForSubmission() { + agHelper.GetNClick(communityTemplates.locators._publishInitiateButton); + + // author details check + const testUserName = "Demo user"; + const testUserEmail = "demo-user@appsmith.com"; + + communityTemplates.AssertChangeAuthorDetailsDisablesSubmit( + communityForm.author.name, + testUserName, + ); + communityTemplates.AssertChangeAuthorDetailsDisablesSubmit( + communityForm.author.email, + testUserEmail, + ); + // tnC check + agHelper.CheckUncheck(communityForm.tnCCheckbox, true); + communityTemplates.AssertPublishButtonState(false); + } + + it("1. Clicking close on modal header in template form should hide the share modal", () => { + agHelper.GetNClick(communityTemplates.locators._publishInitiateButton); + agHelper.GetNClick(locators._dialogCloseButton); + agHelper.AssertElementAbsence(communityTemplates.locators._dialogBox); + }); + + it("2. Form Validation", () => { + agHelper.GetNClick(communityTemplates.locators._publishInitiateButton); + // Initial name check + communityTemplates.AssertInputValueToEqualPreviewValue( + communityForm.inputs.name, + communityForm.preview.name, + ); + //Empty name should disable publish + agHelper.UpdateInputValue(communityForm.inputs.name, ""); + communityTemplates.AssertPublishButtonState(true); + //Update name input, updates preview + const testName = "My first template"; + agHelper.UpdateInputValue(communityForm.inputs.name, testName); + communityTemplates.AssertInputValueToEqualPreviewValue( + communityForm.inputs.name, + communityForm.preview.name, + ); + //Update excerpt input, updates preview + const testExcerpt = "Small description of my template"; + agHelper.UpdateInputValue(communityForm.inputs.excerpt, testExcerpt); + communityTemplates.AssertInputValueToEqualPreviewValue( + communityForm.inputs.excerpt, + communityForm.preview.excerpt, + ); + + // author details check + const testUserName = "Rahul Barwal"; + const testUserEmail = "rahul.barwal@appsmith.com"; + + communityTemplates.AssertChangeAuthorDetailsDisablesSubmit( + communityForm.author.name, + testUserName, + ); + communityTemplates.AssertChangeAuthorDetailsDisablesSubmit( + communityForm.author.email, + testUserEmail, + ); + communityTemplates.AssertPublishButtonState(true); + + // tnC check + agHelper.CheckUncheck(communityForm.tnCCheckbox, true); + communityTemplates.AssertPublishButtonState(false); + + // app settings check + communityTemplates.AssertDisablingAppSettingDisablesSubmit( + communityForm.appSettings.public, + ); + communityTemplates.AssertDisablingAppSettingDisablesSubmit( + communityForm.appSettings.forkable, + ); + }); + + it("3. Publish template happy scenario", () => { + prepareTemplateFormForSubmission(); + + // TODO: Make an API request here and intercept it to happy submission + + agHelper.ValidateToastMessage("Template published to community"); + }); + it("4. Publish template unhappy scenario", () => { + prepareTemplateFormForSubmission(); + + // TODO: Make an API request here and intercept it to unhappy submission + + agHelper.ValidateToastMessage("Unable to publish"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts index 8f993d9090..aa22350549 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts @@ -22,6 +22,7 @@ describe("excludeForAirgap", "JSObjects", () => { entityType: entityItems.JSObject, }); }); + it("2. Focus and position cursor on the ch,line having an error", () => { const JS_OBJECT_BODY = `export default { myVar1: [], @@ -53,4 +54,44 @@ describe("excludeForAirgap", "JSObjects", () => { entityType: entityItems.JSObject, }); }); + + it("3. Bug 24990 Clears logs filter using backspace", function () { + const JS_OBJECT_BODY = `export default { + myVar1: [], + myVar2: {}, + myFun1 () { + // write code here + return [1,2,3] + }, + async myFun2 () { + return [] + } + }`; + jsEditor.CreateJSObject(JS_OBJECT_BODY, { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + }); + jsEditor.SelectFunctionDropdown("myFun1"); + jsEditor.RunJSObj(); + debuggerHelper.ClickLogsTab(); + agHelper.AssertText( + debuggerHelper.locators._debuggerFilter, + "val", + "JSObject1", + ); + agHelper.TypeText( + debuggerHelper.locators._debuggerFilter, + "{backspace}{backspace}{backspace}{backspace}{backspace}{backspace}{backspace}{backspace}{backspace}", + { delay: 50, parseSpecialCharSeq: true }, + ); + agHelper.AssertText(debuggerHelper.locators._debuggerFilter, "val", ""); + debuggerHelper.DebuggerLogsFilter("JSObject1"); + debuggerHelper.DebuggerLogsFilter("{backspace}"); + agHelper.AssertText(debuggerHelper.locators._debuggerFilter, "val", ""); + debuggerHelper.DebuggerLogsFilter("JSObject1"); + agHelper.GetNClick(debuggerHelper.locators._debuggerFilterClear); + agHelper.AssertText(debuggerHelper.locators._debuggerFilter, "val", ""); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Debugger/Widget_property_navigation_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Debugger/Widget_property_navigation_spec.ts index 0148c0811d..c8d0c4826d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Debugger/Widget_property_navigation_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Debugger/Widget_property_navigation_spec.ts @@ -73,15 +73,26 @@ describe("excludeForAirgap", "Widget property navigation", () => { }); it("5. JSONForm widget error navigation", () => { + const schema = { + name: "John", + date_of_birth: "20/02/1990", + employee_id: 1001, + }; _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.JSONFORM); + _.propPane.EnterJSContext( + "sourcedata", + JSON.stringify(schema), + true, + false, + ); _.propPane.OpenTableColumnSettings("date_of_birth"); - _.agHelper.SelectDropdownList("Field Type", "Object"); + _.propPane.SelectPropertiesDropDown("Field Type", "Object"); _.agHelper.GetNClick(_.propPane._addColumnItem); _.agHelper.GetNClick(_.propPane._addColumnItem); _.propPane.OpenTableColumnSettings("customField1"); - _.agHelper.SelectDropdownList("Field Type", "Object"); + _.propPane.SelectPropertiesDropDown("Field Type", "Object"); _.agHelper.GetNClick(_.propPane._addColumnItem); _.agHelper.GetNClick(_.propPane._addColumnItem); _.propPane.OpenTableColumnSettings("customField2"); @@ -143,7 +154,7 @@ describe("excludeForAirgap", "Widget property navigation", () => { _.agHelper.Sleep(3000); //for tables to populate for CI runs _.agHelper.GetNClick(OneClickBindingLocator.tableOrSpreadsheetDropdown); _.agHelper.GetNClick( - OneClickBindingLocator.tableOrSpreadsheetDropdownOption(), + OneClickBindingLocator.tableOrSpreadsheetDropdownOption("movies"), ); _.agHelper.GetNClick(OneClickBindingLocator.searchableColumn); _.agHelper.GetNClick( diff --git a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/List_TextWidget_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/List_TextWidget_Spec.ts index 70644210ab..047380b19c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/List_TextWidget_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/List_TextWidget_Spec.ts @@ -9,7 +9,6 @@ import { describe("Dynamic Height Width validation list widget", function () { it("1. Validate change with auto height width for list widgets", function () { - const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; const textMsg = "Dynamic panel validation for text widget wrt height"; agHelper.AddDsl("DynamicHeightListTextDsl"); @@ -17,16 +16,12 @@ describe("Dynamic Height Width validation list widget", function () { entityExplorer.SelectEntityByName("List1", "Widgets"); //Widgets which were not possible to be added to list widget cannot be pasted/moved into the list widget with multitreeselect entityExplorer.SelectEntityByName("MultiTreeSelect1", "List1"); - agHelper.TypeText(locators._body, `{${modifierKey}}c`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("copy"); agHelper.WaitUntilAllToastsDisappear(); agHelper.Sleep(2000); entityExplorer.SelectEntityByName("List1", "Widgets"); propPane.MoveToTab("Style"); - agHelper.TypeText(locators._body, `{${modifierKey}}v`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("paste"); agHelper.ValidateToastMessage( "This widget cannot be used inside the list widget.", 0, @@ -34,7 +29,7 @@ describe("Dynamic Height Width validation list widget", function () { ); agHelper .GetWidgetCSSHeight(locators._widgetInDeployed(draggableWidgets.LIST)) - .then((currentListHeight: number) => { + .then((currentListHeight: any) => { //Widgets within list widget have no dynamic height agHelper.AssertElementAbsence(propPane._propertyPaneHeightLabel); //Widgets within list widget in existing applications have no dynamic height @@ -49,7 +44,7 @@ describe("Dynamic Height Width validation list widget", function () { propPane.UpdatePropertyFieldValue("Text", textMsg, true); agHelper .GetWidgetCSSHeight(locators._widgetInDeployed(draggableWidgets.LIST)) - .then((updatedListHeight: number) => { + .then((updatedListHeight: any) => { expect(currentListHeight).to.equal(updatedListHeight); }); entityExplorer.SelectEntityByName("Container1", "List1"); @@ -58,34 +53,29 @@ describe("Dynamic Height Width validation list widget", function () { //Widgets when moved into the list widget have no dynamic height entityExplorer.SelectEntityByName("Text3", "Widgets"); propPane.MoveToTab("Style"); - agHelper.TypeText(locators._body, `{${modifierKey}}c`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("copy"); + entityExplorer.SelectEntityByName("List1", "Widgets"); propPane.MoveToTab("Style"); - agHelper.TypeText(locators._body, `{${modifierKey}}v`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("paste"); assertHelper.AssertNetworkStatus("@updateLayout", 200); - entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.SelectEntityByName("Text3Copy"); agHelper.AssertElementAbsence(propPane._propertyPaneHeightLabel); - agHelper.TypeText(locators._body, `{${modifierKey}}c`, { - parseSpecialCharSeq: true, - }); - //agHelper.GetElement(locators._body).click({ force: true }); - agHelper.GetElement(locators._canvasBody).click({ force: true }); - agHelper.TypeText(locators._body, `{${modifierKey}}v`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("copy"); + agHelper.WaitUntilAllToastsDisappear(); + agHelper.Sleep(2000); + agHelper.GetNClick(locators._canvasBody); + agHelper.SimulateCopyPaste("paste"); assertHelper.AssertNetworkStatus("@updateLayout"); //Widgets when moved out of the list widget have dynamic height in property pane entityExplorer.SelectEntityByName("Text3CopyCopy", "Widgets"); agHelper.AssertElementVisibility(propPane._propertyPaneHeightLabel); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.TEXT)); agHelper .GetWidgetCSSHeight(locators._widgetInDeployed(draggableWidgets.TEXT)) - .then((height: number) => { + .then((height: any) => { propPane.SelectPropertiesDropDown("height", "Auto Height"); assertHelper.AssertNetworkStatus("@updateLayout", 200); agHelper.GetNClick( @@ -96,33 +86,29 @@ describe("Dynamic Height Width validation list widget", function () { locators._widgetInDeployed(draggableWidgets.TEXT), ) .wait(1000) - .then((updatedListHeight: number) => { + .then((updatedListHeight: any) => { expect(height).to.not.equal(updatedListHeight); }); }); entityExplorer.SelectEntityByName("Text3CopyCopy", "Widgets"); - agHelper.TypeText(locators._body, `{${modifierKey}}c`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("copy"); + entityExplorer.SelectEntityByName("List1", "Widgets"); propPane.MoveToTab("Style"); - agHelper.TypeText(locators._body, `{${modifierKey}}v`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("paste"); assertHelper.AssertNetworkStatus("@updateLayout", 200); //Widgets when copied and pasted into the list widget no longer have dynamic height entityExplorer.SelectEntityByName("Text3CopyCopyCopy", "Container1"); agHelper.AssertElementAbsence(propPane._propertyPaneHeightLabel); + agHelper.Sleep(2000); //wait a bit to ensure that the 'Text3CopyCopy' is selected for cut + entityExplorer.SelectEntityByName("Text3CopyCopy"); - agHelper.TypeText(locators._body, `{${modifierKey}}x`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("cut"); entityExplorer.SelectEntityByName("List1"); propPane.MoveToTab("Style"); agHelper.Sleep(500); - agHelper.TypeText(locators._body, `{${modifierKey}}v`, { - parseSpecialCharSeq: true, - }); + agHelper.SimulateCopyPaste("paste"); + assertHelper.AssertNetworkStatus("@updateLayout", 200); entityExplorer.SelectEntityByName("Text3CopyCopy", "Widgets"); agHelper.AssertElementAbsence(propPane._propertyPaneHeightLabel); diff --git a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Tab_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Tab_spec.ts index 60bc817426..d3c1261c91 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Tab_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Tab_spec.ts @@ -19,6 +19,7 @@ describe("Dynamic Height Width validation for Tab widget", function () { .GetWidgetCSSHeight(locators._widgetInDeployed(draggableWidgets.TAB)) .then((currentHeight: number) => { agHelper.GetNClick(propPane._tabId2); + agHelper.Sleep(1000); agHelper .GetWidgetCSSHeight(locators._widgetInDeployed(draggableWidgets.TAB)) .then((updatedHeight: number) => { @@ -42,6 +43,7 @@ describe("Dynamic Height Width validation for Tab widget", function () { .GetWidgetCSSHeight(locators._widgetInDeployed(draggableWidgets.TAB)) .then((currentHeight) => { agHelper.GetNClick(propPane._tabId2); + agHelper.Sleep(1000); agHelper .GetWidgetCSSHeight(locators._widgetInDeployed(draggableWidgets.TAB)) .then((updatedHeight: number) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/EmbedSettings/EmbedSettings_spec.js b/app/client/cypress/e2e/Regression/ClientSide/EmbedSettings/EmbedSettings_spec.js index 3656390f20..5768935aa2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/EmbedSettings/EmbedSettings_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/EmbedSettings/EmbedSettings_spec.js @@ -3,7 +3,6 @@ import adminSettings from "../../../../locators/AdminsSettings"; const appNavigationLocators = require("../../../../locators/AppNavigation.json"); describe("Embed settings options", function () { - let deployUrl; const getIframeBody = () => { // get the iframe > document > body // and retry until the body element is not empty @@ -63,7 +62,7 @@ describe("Embed settings options", function () { ) .click() .wait(1000); - cy.get("[data-testid='copy-application-url']").last().click(); + _.agHelper.ClickButton("Copy application url"); cy.window() .its("navigator.clipboard") .invoke("readText") @@ -76,7 +75,7 @@ describe("Embed settings options", function () { _.deployMode.NavigateToHomeDirectly(); }); - it("1. Limit embedding", function () { + it("1. Limit embedding then Allow embedding everywhere then Disable everywhere", function () { cy.get(".admin-settings-menu-option").click(); cy.get(".t--admin-settings-APPSMITH_ALLOWED_FRAME_ANCESTORS").within(() => { cy.get("input").eq(1).click(); @@ -84,17 +83,16 @@ describe("Embed settings options", function () { }); cy.get(adminSettings.saveButton).click(); cy.waitForServerRestart(); + _.agHelper.Sleep(2000); cy.get("@deployUrl").then((depUrl) => { cy.log("deployUrl is " + depUrl); - deployUrl = depUrl; - cy.visit(deployUrl, { timeout: 60000 }); + cy.visit(depUrl, { timeout: 60000 }); }); getIframeBody().contains("Submit").should("exist"); - ValidateEditModeSetting(_.embedSettings.locators._restrictedText); - }); + // }); - it("2. Allow embedding everywhere", function () { + // it("2. Allow embedding everywhere", function () { _.homePage.NavigateToHome(); cy.get(".admin-settings-menu-option").click(); cy.get(".t--admin-settings-APPSMITH_ALLOWED_FRAME_ANCESTORS").within(() => { @@ -109,13 +107,16 @@ describe("Embed settings options", function () { // } = interception[1].response.body.data; // expect(APPSMITH_ALLOWED_FRAME_ANCESTORS).to.equal("*"); // }); - cy.log("deployUrl is " + deployUrl); - cy.visit(deployUrl, { timeout: 60000 }); + _.agHelper.Sleep(2000); + cy.get("@deployUrl").then((depUrl) => { + cy.log("deployUrl is " + depUrl); + cy.visit(depUrl, { timeout: 60000 }); + }); getIframeBody().contains("Submit").should("exist"); ValidateEditModeSetting(_.embedSettings.locators._allowAllText); - }); + // }); - it("3. Disable everywhere", function () { + // it("3. Disable everywhere", function () { _.homePage.NavigateToHome(); cy.get(".admin-settings-menu-option").click(); cy.get(".t--admin-settings-APPSMITH_ALLOWED_FRAME_ANCESTORS").within(() => { @@ -123,9 +124,11 @@ describe("Embed settings options", function () { }); cy.get(adminSettings.saveButton).click(); cy.waitForServerRestart(); - cy.log("deployUrl is " + deployUrl); - cy.visit(deployUrl, { timeout: 60000 }); - // TODO: Commented out as it is flaky + _.agHelper.Sleep(2000); + cy.get("@deployUrl").then((depUrl) => { + cy.log("deployUrl is " + depUrl); + cy.visit(depUrl, { timeout: 60000 }); + }); // TODO: Commented out as it is flaky // cy.wait(["@getEnvVariables", "@getEnvVariables"]).then((interception) => { // const { // APPSMITH_ALLOWED_FRAME_ANCESTORS, diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_1_spec.js index 28e19fae75..2e5524d998 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_1_spec.js @@ -12,7 +12,7 @@ const routes = { SETTINGS: "/settings", GENERAL: "/settings/general", EMAIL: "/settings/email", - GOOGLE_MAPS: "/settings/google-maps", + DEVELOPER_SETTINGS: "/settings/developer-settings", AUTHENTICATION: "/settings/authentication", GOOGLEAUTH: "/settings/authentication/google-auth", GITHUBAUTH: "/settings/authentication/github-auth", @@ -45,8 +45,8 @@ describe("Admin settings page", function () { it("2. should test that page header is visible", () => { cy.get(adminsSettings.appsmithHeader).should("be.visible"); - cy.visit(routes.GOOGLE_MAPS, { timeout: 60000 }); - cy.url().should("contain", "/google-maps"); + cy.visit(routes.DEVELOPER_SETTINGS, { timeout: 60000 }); + cy.url().should("contain", "/developer-settings"); cy.wait(2000); //page to load properly cy.get(adminsSettings.appsmithHeader).should("be.visible"); cy.visit(routes.GOOGLEAUTH, { timeout: 60000 }); @@ -84,8 +84,8 @@ describe("Admin settings page", function () { cy.url().should("contain", routes.AUTHENTICATION); cy.get(adminsSettings.emailTab).click(); cy.url().should("contain", routes.EMAIL); - cy.get(adminsSettings.googleMapsTab).click(); - cy.url().should("contain", routes.GOOGLE_MAPS); + cy.get(adminsSettings.developerSettingsTab).click(); + cy.url().should("contain", routes.DEVELOPER_SETTINGS); cy.get(adminsSettings.versionTab).click(); cy.url().should("contain", routes.VERSION); }, @@ -105,7 +105,7 @@ describe("Admin settings page", function () { cy.get(adminsSettings.authenticationTab).click(); cy.url().should("contain", routes.AUTHENTICATION); cy.get(adminsSettings.emailTab).click(); - cy.get(adminsSettings.googleMapsTab).should("not.exist"); + cy.get(adminsSettings.developerSettingsTab).should("not.exist"); cy.url().should("contain", routes.EMAIL); cy.get(adminsSettings.versionTab).click(); cy.url().should("contain", routes.VERSION); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_2_spec.js index 70020fe1e6..86695fa129 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Admin_settings_2_spec.js @@ -12,7 +12,7 @@ const routes = { SETTINGS: "/settings", GENERAL: "/settings/general", EMAIL: "/settings/email", - GOOGLE_MAPS: "/settings/google-maps", + DEVELOPER_SETTINGS: "/settings/developer-settings", AUTHENTICATION: "/settings/authentication", GOOGLEAUTH: "/settings/authentication/google-auth", GITHUBAUTH: "/settings/authentication/github-auth", @@ -23,7 +23,7 @@ const routes = { describe("Admin settings page", function () { it("1. should test that configure link redirects to google maps setup doc", () => { - cy.visit(routes.GOOGLE_MAPS, { timeout: 60000 }); + cy.visit(routes.DEVELOPER_SETTINGS, { timeout: 60000 }); cy.get(adminsSettings.readMoreLink).within(() => { cy.get("a") .should("have.attr", "target", "_blank") @@ -144,13 +144,13 @@ describe("Admin settings page", function () { ); it("6. should test that settings page is not accessible to normal users", () => { - cy.LogOut(); + cy.LogOut(false); cy.wait(2000); cy.LoginFromAPI(Cypress.env("TESTUSERNAME3"), Cypress.env("TESTPASSWORD3")); cy.get(".admin-settings-menu-option").should("not.exist"); cy.visit(routes.GENERAL, { timeout: 60000 }); // non super users are redirected to home page cy.url().should("contain", routes.APPLICATIONS); - cy.LogOut(); + cy.LogOut(false); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Datasource_Structure_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Datasource_Structure_spec.js index 1222949624..1b4607bf2a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Datasource_Structure_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Datasource_Structure_spec.js @@ -54,9 +54,11 @@ describe("Entity explorer datasource structure", function () { // cy.get(".bp3-popover-content").should("be.visible"); cy.get(explorer.templateMenuIcon).first().click({ force: true }); + // assert suggested tag is present + cy.get(".t--structure-template-menu-popover").last().contains("Suggested"); cy.get(".t--structure-template-menu-popover") .last() - .contains("SELECT") + .contains("Select") .click({ force: true }); cy.wait("@createNewApi").should( "have.nested.property", @@ -105,42 +107,18 @@ describe("Entity explorer datasource structure", function () { // cy.xpath(explorer.datsourceEntityPopover) // .last() // .click({ force: true }); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: datasourceName, - action: "Refresh", - }); - cy.wait("@getDatasourceStructure").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, + dataSources.AssertTableInVirtuosoList( + datasourceName, + `public.${tableName}`, ); - // Expand datasource - // cy.get(`.t--entity.datasource:contains(${datasourceName})`) - // .find(explorer.collapse) - // .first() - // .click(); - entityExplorer.AssertEntityPresenceInExplorer(`public.${tableName}`); - - // cy.get(explorer.refreshStructure).click({ force: true }); - // TODO (Akash): Check for new table name to be visible in UI as well - // cy.get(explorer.datasourceStructure) - // .contains(`public.${tableName}`) - // .should("be.visible"); cy.typeValueNValidate(`DROP TABLE public.${tableName}`); cy.runQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: datasourceName, - action: "Refresh", - }); - cy.wait("@getDatasourceStructure").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, + dataSources.AssertTableInVirtuosoList( + datasourceName, + `public.${tableName}`, + false, ); - entityExplorer.AssertEntityAbsenceInExplorer(`public.${tableName}`); cy.deleteQueryUsingContext(); cy.deleteDatasource(datasourceName); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Pin_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Pin_spec.js index 8baf453b66..3269a17033 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Pin_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Pin_spec.js @@ -10,8 +10,8 @@ import { const ExplorerMenu = { ADD_PAGE: "ADD_PAGE", ENTITY: "ENTITY", - ADD_QUERY_JS: "ADD_QUERY_JS", ADD_LIBRARY: "ADD_LIBRARY", + ADD_QUERY_JS: "ADD_QUERY_JS", }; const OpenExplorerMenu = (menu) => { @@ -109,9 +109,12 @@ describe("Entity explorer tests related to pinning and unpinning", function () { function () { agHelper.AssertElementVisibility(entityExplorer._entityExplorer); entityExplorer.PinUnpinEntityExplorer(true); - const menu = Object.keys(ExplorerMenu); + // We cannot add libraries on airgap + const menu = Object.keys(ExplorerMenu).filter( + (menu) => menu !== ExplorerMenu.ADD_LIBRARY, + ); - Cypress._.times(menu.length - 1, (index) => { + Cypress._.times(menu.length, (index) => { OpenExplorerMenu(menu[index]); agHelper.Sleep(); cy.get("[data-testid=sidebar-active]").should("exist"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Scrolling_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Scrolling_Spec.ts index 60a9ae9b5a..f2daf9a419 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Scrolling_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Scrolling_Spec.ts @@ -1,6 +1,7 @@ import { agHelper, dataSources, + draggableWidgets, entityExplorer, entityItems, locators, @@ -12,6 +13,16 @@ describe("Entity explorer context menu should hide on scrolling", function () { "excludeForAirgap", "1. Bug #15474 - Entity explorer menu must close on scroll", function () { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MODAL); + agHelper.GetNClick(locators._closeModal, 0, true, 0); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MODAL); + agHelper.GetNClick(locators._closeModal, 0, true, 0); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MODAL); + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.ExpandCollapseEntity("Modal1"); + entityExplorer.ExpandCollapseEntity("Modal2"); + entityExplorer.ExpandCollapseEntity("Modal3"); + // Setup to make the explorer scrollable entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.ExpandCollapseEntity("Datasources"); @@ -20,19 +31,15 @@ describe("Entity explorer context menu should hide on scrolling", function () { cy.log("Users DB created is " + $createdMockUsers); mockDBNameUsers = $createdMockUsers; dataSources.CreateQueryAfterDSSaved(); + dataSources.AssertTableInVirtuosoList(mockDBNameUsers, "public.users"); dataSources.CreateMockDB("Movies").then(($createdMockMovies) => { cy.log("Movies DB created is " + $createdMockMovies); mockDBNameMovies = $createdMockMovies; dataSources.CreateQueryAfterDSSaved(); - agHelper.Sleep(); - entityExplorer.ExpandCollapseEntity(mockDBNameUsers); - agHelper.Sleep(); - entityExplorer.ExpandCollapseEntity(mockDBNameMovies); + dataSources.AssertTableInVirtuosoList(mockDBNameMovies, "movies"); - entityExplorer.ExpandCollapseEntity("public.users"); - entityExplorer.ExpandCollapseEntity("movies"); agHelper.GetNClick(locators._createNew); agHelper.AssertElementVisibility(entityExplorer._adsPopup); agHelper.ScrollTo(entityExplorer._entityExplorerWrapper, "bottom"); @@ -46,6 +53,16 @@ describe("Entity explorer context menu should hide on scrolling", function () { "airgap", "1. Bug #15474 - Entity explorer menu must close on scroll - airgap", function () { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MODAL); + agHelper.GetNClick(locators._closeModal, 0, true, 0); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MODAL); + agHelper.GetNClick(locators._closeModal, 0, true, 0); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MODAL); + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.ExpandCollapseEntity("Modal1"); + entityExplorer.ExpandCollapseEntity("Modal2"); + entityExplorer.ExpandCollapseEntity("Modal3"); + // Setup to make the explorer scrollable entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.ExpandCollapseEntity("Datasources"); @@ -55,18 +72,18 @@ describe("Entity explorer context menu should hide on scrolling", function () { mockDBNameUsers = $createdMockUsers; dataSources.CreateQueryAfterDSSaved(); + dataSources.AssertTableInVirtuosoList(mockDBNameUsers, "public.users"); + dataSources.CreateDataSource("Mongo"); cy.get("@dsName").then(($createdMockMovies: any) => { mockDBNameMovies = $createdMockMovies; dataSources.CreateQueryAfterDSSaved(); - agHelper.Sleep(); - entityExplorer.ExpandCollapseEntity(mockDBNameUsers); - agHelper.Sleep(); - entityExplorer.ExpandCollapseEntity(mockDBNameMovies); + dataSources.AssertTableInVirtuosoList( + mockDBNameMovies, + "listingAndReviews", + ); - entityExplorer.ExpandCollapseEntity("public.users"); - entityExplorer.ExpandCollapseEntity("listingAndReviews"); agHelper.GetNClick(locators._createNew); agHelper.AssertElementVisibility(entityExplorer._adsPopup); agHelper.ScrollTo(entityExplorer._entityExplorerWrapper, "bottom"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Paste_Delete_Undo_Keyboard_Event_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Paste_Delete_Undo_Keyboard_Event_spec.js index c1ff5ece8c..6a81933cd4 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Paste_Delete_Undo_Keyboard_Event_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Paste_Delete_Undo_Keyboard_Event_spec.js @@ -58,5 +58,6 @@ describe("Test Suite to validate copy/delete/undo functionalites", function () { cy.get(".bp3-input").first().click({ force: true }); cy.get(".bp3-input").first().type(`{${modifierKey}}v`, { force: true }); }); + agHelper.RemoveUIElement("Toast", "7 widgets are added back."); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Sidebar.ts b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Sidebar.ts index eae6058547..f355fe9068 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Sidebar.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Sidebar.ts @@ -1,4 +1,3 @@ -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import { entityExplorer, agHelper, @@ -59,16 +58,6 @@ describe("Entity explorer tests related to widgets and validation", function () WIDGETS_CATALOG.Content = ["Progress", "Rating", "Text"]; } - before(() => { - featureFlagIntercept( - { - release_widgetdiscovery_enabled: true, - }, - false, - ); - agHelper.RefreshPage(); - }); - const getTotalNumberOfWidgets = () => { return Object.values(WIDGETS_CATALOG).reduce( (totalLength, widgets) => totalLength + widgets.length, diff --git a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkAppWithMultipleDS_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkAppWithMultipleDS_Spec.ts index 62a72547ce..8cb92c48c6 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkAppWithMultipleDS_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkAppWithMultipleDS_Spec.ts @@ -3,7 +3,6 @@ import { dataSources, homePage, } from "../../../../support/Objects/ObjectsCore"; -import reconnectDSLocator from "../../../../locators/ReconnectLocators.js"; let workspaceId: string; @@ -31,7 +30,7 @@ describe("Fork application with multiple datasources", function () { it("1. Bug Id: 24708 - fork and test the forked application", function () { // Create a new workspace and fork application - const appname: string = localStorage.getItem("AppName") || "randomApp"; + const appname: string = localStorage.getItem("appName") || "randomApp"; agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { workspaceId = "forkApp" + uid; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationInDeployedMode_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationInDeployedMode_spec.ts new file mode 100644 index 0000000000..f7e9552e5d --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationInDeployedMode_spec.ts @@ -0,0 +1,31 @@ +import { + agHelper, + appSettings, + deployMode, + embedSettings, +} from "../../../../support/Objects/ObjectsCore"; +import applicationLocators from "../../../../locators/Applications.json"; + +describe("Fork application in deployed mode", function () { + it("1. Fork modal should open and close", function () { + appSettings.OpenAppSettings(); + appSettings.GoToEmbedSettings(); + embedSettings.ToggleMarkForkable(); + embedSettings.TogglePublicAccess(); + deployMode.DeployApp(); + + cy.url().then((url) => { + const forkableAppUrl = url; + cy.LogOut(); + cy.LogintoApp(Cypress.env("TESTUSERNAME1"), Cypress.env("TESTPASSWORD1")); + cy.visit(forkableAppUrl); + + agHelper.GetNClick(applicationLocators.forkButton); + cy.wait(2000); + agHelper.AssertElementVisibility(applicationLocators.forkModal); + cy.location("search").should("include", "fork=true"); + agHelper.GetNClick(applicationLocators.closeModalPopup); + cy.location("search").should("not.include", "fork=true"); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationWithinAppEditor_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationWithinAppEditor_spec.ts index 5b8a4d76a8..d790b55052 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationWithinAppEditor_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationWithinAppEditor_spec.ts @@ -9,7 +9,8 @@ describe("Fork application across workspaces", function () { }); it("1. Signed user should be able to fork a public forkable app & Check if the forked application has the same dsl as the original", function () { - const appname: string = localStorage.getItem("AppName") || "randomApp"; + const appname: string = + localStorage.getItem("workspaceName") || "randomApp"; _.entityExplorer.SelectEntityByName("Input1"); cy.intercept("PUT", "/api/v1/layouts/*/pages/*").as("inputUpdate"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplication_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplication_spec.ts index 8691fe806a..f99a584923 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplication_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplication_spec.ts @@ -1,9 +1,20 @@ -import homePage from "../../../../locators/HomePage"; import applicationLocators from "../../../../locators/Applications.json"; import signupPageLocators from "../../../../locators/SignupPage.json"; import loginPageLocators from "../../../../locators/LoginPage.json"; import reconnectDatasourceModal from "../../../../locators/ReconnectLocators"; -import * as _ from "../../../../support/Objects/ObjectsCore"; +import homepagelocators from "../../../../locators/HomePage"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; +import { + appSettings, + entityExplorer, + deployMode, + agHelper, + fakerHelper, + inviteModal, + embedSettings, + homePage, + locators, +} from "../../../../support/Objects/ObjectsCore"; let forkedApplicationDsl; let parentApplicationDsl; @@ -11,12 +22,12 @@ let forkableAppUrl; describe("Fork application across workspaces", function () { before(() => { - _.agHelper.AddDsl("basicDsl"); + agHelper.AddDsl("basicDsl"); }); it("1. Check if the forked application has the same dsl as the original", function () { - const appname = localStorage.getItem("AppName"); - _.entityExplorer.SelectEntityByName("Input1"); + const appname = localStorage.getItem("workspaceName"); + entityExplorer.SelectEntityByName("Input1"); cy.intercept("PUT", "/api/v1/layouts/*/pages/*").as("inputUpdate"); cy.testJsontext("defaultvalue", "A"); @@ -25,13 +36,13 @@ describe("Fork application across workspaces", function () { }); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(2000); - _.homePage.NavigateToHome(); - cy.get(homePage.searchInput).type(appname); + homePage.NavigateToHome(); + cy.get(homepagelocators.searchInput).type(appname); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(2000); - cy.get(homePage.appMoreIcon).first().click({ force: true }); - cy.get(homePage.forkAppFromMenu).click({ force: true }); - cy.get(homePage.forkAppWorkspaceButton).click({ force: true }); + cy.get(homepagelocators.appMoreIcon).first().click({ force: true }); + cy.get(homepagelocators.forkAppFromMenu).click({ force: true }); + cy.get(homepagelocators.forkAppWorkspaceButton).click({ force: true }); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(4000); cy.wait("@postForkAppWorkspace") @@ -51,12 +62,12 @@ describe("Fork application across workspaces", function () { }); it("2. Non signed user should be able to fork a public forkable app", function () { - _.homePage.NavigateToHome(); - cy.get(homePage.homeIcon).click(); - cy.get(homePage.optionsIcon).first().click(); - cy.get(homePage.workspaceImportAppOption).click({ force: true }); - cy.get(homePage.workspaceImportAppModal).should("be.visible"); - cy.xpath(homePage.uploadLogo).selectFile( + homePage.NavigateToHome(); + cy.get(homepagelocators.homeIcon).click(); + cy.get(homepagelocators.optionsIcon).first().click(); + cy.get(homepagelocators.workspaceImportAppOption).click({ force: true }); + cy.get(homepagelocators.workspaceImportAppModal).should("be.visible"); + cy.xpath(homepagelocators.uploadLogo).selectFile( "cypress/fixtures/forkNonSignedInUser.json", { force: true }, ); @@ -71,8 +82,8 @@ describe("Fork application across workspaces", function () { cy.wait(2000); } cy.get("#sidebar").should("be.visible"); - _.deployMode.DeployApp(); - _.agHelper.Sleep(2000); + deployMode.DeployApp(); + agHelper.Sleep(2000); cy.get("button:contains('Share')").first().click({ force: true }); // _.agHelper.Sleep(1000); // cy.get("body").then(($ele) => { @@ -95,44 +106,44 @@ describe("Fork application across workspaces", function () { cy.wait(4000); cy.get(applicationLocators.forkButton).first().click({ force: true }); cy.get(loginPageLocators.signupLink).click(); - cy.generateUUID().then((uid) => { cy.get(signupPageLocators.username).type(`${uid}@appsmith.com`); cy.get(signupPageLocators.password).type(uid); cy.get(signupPageLocators.submitBtn).click(); cy.wait(10000); cy.get(applicationLocators.forkButton).first().click({ force: true }); - cy.get(homePage.forkAppWorkspaceButton).should("be.visible"); - _.agHelper.GetNClick(_.locators._dialogCloseButton); - cy.LogOut(); - cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); - _.homePage.CreateNewApplication(); + cy.get(homepagelocators.forkAppWorkspaceButton).should("be.visible"); }); }); }); }); - it.skip("Mark application as forkable", () => { - _.appSettings.OpenAppSettings(); - _.appSettings.GoToEmbedSettings(); - _.embedSettings.ToggleMarkForkable(); + it("3. Mark application as forkable", () => { + homePage.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + featureFlagIntercept({ license_gac_enabled: true }); + cy.wait(2000); + homePage.CreateNewApplication(); + appSettings.OpenAppSettings(); + appSettings.GoToEmbedSettings(); + embedSettings.ToggleMarkForkable(); + embedSettings.TogglePublicAccess(); - _.inviteModal.OpenShareModal(); - _.homePage.InviteUserToApplication( - Cypress.env("TESTUSERNAME1"), + inviteModal.OpenShareModal(); + homePage.InviteUserToApplication( + fakerHelper.GetRandomText(5) + "@appsmith.com", "App Viewer", - false, ); - _.inviteModal.CloseModal(); - _.deployMode.DeployApp(); + inviteModal.CloseModal(); + deployMode.DeployApp(); + cy.url().then((url) => { forkableAppUrl = url; cy.LogOut(); cy.LogintoApp(Cypress.env("TESTUSERNAME1"), Cypress.env("TESTPASSWORD1")); cy.visit(forkableAppUrl); - _.agHelper.AssertElementVisibility(applicationLocators.forkButton); + agHelper.AssertElementVisibility(applicationLocators.forkButton); }); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/FormLogin/EmailVerfication_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/FormLogin/EmailVerfication_spec.ts new file mode 100644 index 0000000000..dbf85416aa --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/FormLogin/EmailVerfication_spec.ts @@ -0,0 +1,126 @@ +import adminsSettings from "../../../../locators/AdminsSettings"; + +describe("Email verification", () => { + it("1. Shows the email verification pending page correctly", () => { + cy.LogOut(); + cy.visit("/user/verificationPending?email=test@appsmith.com"); + cy.wait(1000); + cy.get("[data-testid='verification-pending']").matchImageSnapshot( + "VerificationPendingScreen", + ); + }); + + it("2. Verification error pages", () => { + const errorCode = { + ALREADY_VERIFIED: "AE-EMV-4095", + EXPIRED: "AE-EMV-4096", + MISMATCH: "AE-EMV-4098", + UNKNOWN: "UNKNOWN", + }; + cy.visit( + `/user/verify-error?email=abc&code=${errorCode.MISMATCH}&message=xyz`, + ); + cy.wait(1000); + cy.get("[data-testid='verification-error']").matchImageSnapshot( + "WrongToken", + ); + cy.visit( + `/user/verify-error?email=abc&code=${errorCode.ALREADY_VERIFIED}&message=xyz`, + ); + cy.wait(1000); + cy.get("[data-testid='verification-error']").matchImageSnapshot( + "Verified Token", + ); + cy.visit( + `/user/verify-error?email=abc&code=${errorCode.EXPIRED}&message=xyz`, + ); + cy.wait(1000); + cy.get("[data-testid='verification-error']").matchImageSnapshot( + "Expired Token", + ); + cy.visit( + `/user/verify-error?email=abc&code=${errorCode.UNKNOWN}&message=xyz`, + ); + cy.wait(1000); + cy.get("[data-testid='verification-error']").matchImageSnapshot( + "Unknown error", + ); + }); + + //Skipping since Server restart taking a lot of time + it.skip("3. Email verification settings test", () => { + cy.LogOut(); + cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + cy.get(".admin-settings-menu-option").should("be.visible"); + cy.get(".admin-settings-menu-option").click(); + cy.url().should("contain", "/settings/general"); + cy.wait("@getEnvVariables"); + cy.get(adminsSettings.authenticationTab).click(); + cy.get(adminsSettings.formloginButton).click(); + //cy.pause(); + // Assert verification is disabled + cy.get(adminsSettings.enableEmailVerificationInput).should("be.disabled"); + // Assert callout + //cy.get(adminsSettings.adminSettingsCallout).should("be.visible"); + // go to email settings + cy.get(adminsSettings.emailTab).click(); + // add email settings + cy.generateUUID().then((uuid) => { + cy.get(adminsSettings.fromAddress).clear().type(`${uuid}@appsmith.com`); + }); + // save + cy.get(adminsSettings.saveButton).click(); + + cy.waitForServerRestart(); + + cy.waitUntil(() => + cy.contains("General", { timeout: 210000 }).should("be.visible"), + ).then(() => { + cy.wait("@getEnvVariables"); + cy.get(adminsSettings.authenticationTab).click(); + cy.get(adminsSettings.formloginButton).click(); + // Assert verification is enabled + cy.get(adminsSettings.enableEmailVerificationInput).should( + "not.be.disabled", + ); + // Assert callout + cy.get(adminsSettings.adminSettingsCallout).should("be.visible"); + // turn on setting + cy.get(adminsSettings.enableEmailVerificationInput).click(); + // Assert callout + cy.get(adminsSettings.adminSettingsCallout).should("be.visible"); + cy.get(adminsSettings.saveButton).click(); + cy.wait("@postTenantConfig").then((interception) => { + expect(interception.request.body.enableEmailVerification).to.equal( + true, + ); + }); + cy.get(adminsSettings.emailTab).click(); + // remove email settings + cy.get(adminsSettings.saveButton).click(); + cy.waitForServerRestart(); + + cy.waitUntil(() => + cy.contains("General", { timeout: 180000 }).should("be.visible"), + ).then(() => { + cy.wait("@getEnvVariables"); + cy.get(adminsSettings.authenticationTab).click(); + cy.get(adminsSettings.formloginButton).click(); + // Assert verification is enabled + cy.get(adminsSettings.enableEmailVerificationInput).should( + "not.be.disabled", + ); + // Assert callout + cy.get(adminsSettings.adminSettingsCallout).should("be.visible"); + // turn off setting + cy.get(adminsSettings.enableEmailVerificationInput).click(); + // assert verification is disabled + cy.get(adminsSettings.enableEmailVerificationInput).should( + "be.disabled", + ); + // assert callout + cy.get(adminsSettings.adminSettingsCallout).should("be.visible"); + }); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/FormLogin/EnableFormLogin_spec.js b/app/client/cypress/e2e/Regression/ClientSide/FormLogin/EnableFormLogin_spec.js index 0667a2a8a7..68abe6cf2c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/FormLogin/EnableFormLogin_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/FormLogin/EnableFormLogin_spec.js @@ -65,7 +65,7 @@ describe("Form Login test functionality", function () { "excludeForAirgap", "2. Go to admin settings and disable Form Login", function () { - cy.LogOut(); + cy.LogOut(false); cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); cy.openAuthentication(); cy.get(adminSettings.formloginButton) diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts index 9f85a8f646..c27fe53dd7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts @@ -23,17 +23,18 @@ describe("Import and validate older app (app created in older versions of Appsmi cy.get("@guid").then((uid) => { workspaceName = "GitImport_" + uid; homePage.CreateNewWorkspace(workspaceName, true); - }); - //Import App From Gitea - gitSync.ImportAppFromGit(workspaceName, appRepoName, true); - cy.get("@deployKeyId").then((id) => { - keyId = id; + //Import App From Gitea + gitSync.ImportAppFromGit(workspaceName, appRepoName, true); + cy.get("@deployKeyId").then((id) => { + keyId = id; + }); }); //Reconnect datasources dataSources.ReconnectDSbyType("MongoDB"); dataSources.ReconnectDSbyType("MySQL"); dataSources.ReconnectDSbyType("PostgreSQL"); + agHelper.Sleep(3000); //for CI to reconnect successfully homePage.AssertNCloseImport(); }); @@ -42,8 +43,8 @@ describe("Import and validate older app (app created in older versions of Appsmi //Wait for the app to settle agHelper.Sleep(3000); homePage.RenameApplication(appName); - - agHelper.AssertElementVisibility(gitSync._bottomBarCommit); + assertHelper.AssertNetworkResponseData("gitStatus"); + agHelper.AssertElementExist(gitSync._bottomBarCommit, 0, 30000); agHelper.AssertText(gitSync._gitPullCount, "text", "4"); agHelper.GetNClick(gitSync._bottomBarCommit); agHelper.AssertElementVisibility(gitSync._gitSyncModal); @@ -53,11 +54,13 @@ describe("Import and validate older app (app created in older versions of Appsmi gitSync._gitStatusChanges, /[0-9] page(|s) modified/, ); - agHelper.GetNAssertElementText( - gitSync._gitStatusChanges, - "Application settings modified", - "not.contain.text", - ); + + // Commenting it as part of #28012 - to be added back later + // agHelper.GetNAssertElementText( + // gitSync._gitStatusChanges, + // "Application settings modified", + // "not.contain.text", + // ); agHelper.GetNAssertElementText( gitSync._gitStatusChanges, "Theme modified", @@ -73,12 +76,20 @@ describe("Import and validate older app (app created in older versions of Appsmi // ); agHelper.AssertContains(/[0-9] JS Object(|s) modified/, "not.exist"); - agHelper.AssertContains(/[0-9] librar(y|ies) modified/, "not.exist"); - agHelper.GetNAssertElementText( - gitSync._gitStatusChanges, - "Some of the changes above are due to an improved file structure designed to reduce merge conflicts. You can safely commit them to your repository.", - "contain.text", - ); + + // Commenting it as part of #28012 - to be added back later + // agHelper.AssertContains(/[0-9] librar(y|ies) modified/, "not.exist"); + + // This assertions is commented out due to issue #https://github.com/appsmithorg/appsmith/issues/28563 + // Since we don't want this specific message appearing when we are just migrating the metadata, + // this assertion is not required. + // Slack conversation: https://theappsmith.slack.com/archives/C04HERDNZPA/p1698851532418569 + + // agHelper.GetNAssertElementText( + // gitSync._gitStatusChanges, + // "Some of the changes above are due to an improved file structure designed to reduce merge conflicts. You can safely commit them to your repository.", + // "contain.text", + // ); agHelper.GetNClick(gitSync._commitButton); assertHelper.AssertNetworkStatus("@commit", 201); gitSync.CloseGitSyncModal(); @@ -94,6 +105,7 @@ describe("Import and validate older app (app created in older versions of Appsmi "listingAndReviews Data", ); agHelper.AssertElementVisibility(locators._widgetByName("data_table")); + table.WaitUntilTableLoad(0, 0, "v1"); //Filter & validate table data table.OpenNFilterTable("_id", "is exactly", "15665837"); @@ -112,6 +124,7 @@ describe("Import and validate older app (app created in older versions of Appsmi "countryFlags Data", ); agHelper.AssertElementVisibility(locators._widgetByName("data_table")); + table.WaitUntilTableLoad(0, 0, "v1"); //Filter & validate table data table.OpenNFilterTable("Country", "starts with", "Ba"); @@ -132,6 +145,7 @@ describe("Import and validate older app (app created in older versions of Appsmi "public_astronauts Data", ); agHelper.AssertElementVisibility(locators._widgetByName("data_table")); + table.WaitUntilTableLoad(0, 0, "v1"); //Filter & validate table data table.OpenNFilterTable("id", "is exactly", "196"); @@ -145,6 +159,8 @@ describe("Import and validate older app (app created in older versions of Appsmi deployMode.EnterJSONInputValue("Statusname", "Active", 0, true); agHelper.Sleep(500); agHelper.ClickButton("Update"); + agHelper.Sleep(2000); //for CI update to be successful + table.WaitUntilTableLoad(0, 0, "v1"); //Validate updated values in table table.ReadTableRowColumnData(0, 3).then(($cellData) => { @@ -235,6 +251,8 @@ describe("Import and validate older app (app created in older versions of Appsmi agHelper.ClickButton("Confirm"); agHelper.WaitUntilToastDisappear("Delete customer successful!"); agHelper.ClickButton("Close"); + agHelper.AssertElementAbsence(locators._modal); + agHelper.Sleep(2000); }); it("4. Edit JSObject & Check Updated Data ", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js index 535a540b84..1773164809 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js @@ -19,12 +19,13 @@ import { describe("Git import flow ", function () { before(() => { homePage.NavigateToHome(); - cy.createWorkspace(); - cy.wait("@createWorkspace").then((interception) => { - newWorkspaceName = interception.response.body.data.name; - cy.CreateAppForWorkspace(newWorkspaceName, newWorkspaceName); + homePage.CreateNewWorkspace(); + cy.get("@workspaceName").then((workspaceName) => { + newWorkspaceName = workspaceName; + homePage.CreateAppInWorkspace(workspaceName); }); }); + it("1. Import an app from JSON with Postgres, MySQL, Mongo db & then connect it to Git", () => { homePage.NavigateToHome(); cy.get(homePageLocators.optionsIcon).first().click(); @@ -110,7 +111,7 @@ describe("Git import flow ", function () { cy.wait(500); cy.ReconnectDatasource("TEDMongo"); cy.wait(500); - cy.fillMongoDatasourceForm(); + dataSources.FillMongoDSForm(); cy.get(datasourceEditor.sectionAuthentication).click(); cy.testDatasource(true); agHelper.GetNClick(dataSources._saveDs); @@ -147,6 +148,7 @@ describe("Git import flow ", function () { // verify js object binded to input widget cy.xpath("//input[@value='Success']").should("be.visible"); }); + it("4. Create a new branch, clone page and validate data on that branch in view and edit mode", () => { //cy.createGitBranch(newBranch); gitSync.CreateGitBranch(newBranch, true); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Connection_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Connection_spec.js index 58e1627cbf..289dfb2197 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Connection_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Connection_spec.js @@ -5,12 +5,9 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; const httpsRepoURL = "https://github.com/test/test.git"; const invalidURL = "test"; const invalidURLDetectedOnTheBackend = "test@"; - const invalidEmail = "test"; const invalidEmailWithAmp = "test@hello"; -const GITHUB_API_BASE = "https://api.github.com"; - let repoName; let generatedKey; let windowOpenSpy; @@ -59,34 +56,11 @@ describe("Git sync modal: connect tab", function () { cy.intercept("POST", "/api/v1/applications/ssh-keypair/*").as( "generateKey", ); - - // Stubbing window.open - cy.window().then((window) => { - windowOpenSpy = cy.stub(window, "open").callsFake((url) => { - expect(url.startsWith("https://docs.appsmith.com/")).to.be.true; - windowOpenSpy.restore(); - }); - }); - cy.get(gitSyncLocators.learnMoreSshUrl).click(); - cy.get(gitSyncLocators.generateDeployKeyBtn).click(); cy.wait("@generateKey").then((result) => { generatedKey = result.response.body.data.publicKey; }); - - // generate key learn more - cy.window().then((window) => { - windowOpenSpy = cy.stub(window, "open").callsFake((url) => { - expect( - url.startsWith( - "https://docs.github.com/en/developers/overview/managing-deploy-keys", - ), - ).to.be.true; - windowOpenSpy.restore(); - }); - }); - cy.xpath(gitSyncLocators.learnMoreDeployKey).click({ force: true }); }); it("2. validates copy key and validates repo url input after key generation", function () { @@ -95,7 +69,8 @@ describe("Git sync modal: connect tab", function () { }); cy.get(gitSyncLocators.copySshKey).click(); - cy.get(gitSyncLocators.gitRepoInput).type(`{selectAll}${httpsRepoURL}`); + cy.wait(2000); + cy.get(gitSyncLocators.gitRepoInput).clear().type(`${httpsRepoURL}`); cy.contains(Cypress.env("MESSAGES").PASTE_SSH_URL_INFO()); cy.get(gitSyncLocators.connectSubmitBtn).should("be.disabled"); @@ -246,7 +221,7 @@ describe("Git sync modal: connect tab", function () { }); cy.get(gitSyncLocators.connectSubmitBtn).scrollIntoView().click(); - cy.get(gitSyncLocators.connetStatusbar).should("exist"); + // cy.get(gitSyncLocators.connetStatusbar).should("exist"); cy.wait("@connectGitLocalRepo").then((interception) => { const status = interception.response.body.responseMeta.status; expect(status).to.be.gte(400); @@ -254,7 +229,7 @@ describe("Git sync modal: connect tab", function () { }); // read document clicking test - cy.get(gitSyncLocators.errorCallout).contains("Learn More"); + cy.get(gitSyncLocators.errorCallout).contains("Learn more"); cy.window().then((window) => { windowOpenSpy = cy.stub(window, "open").callsFake((url) => { // todo: check if we can improve this @@ -262,12 +237,11 @@ describe("Git sync modal: connect tab", function () { windowOpenSpy.restore(); }); }); - cy.get(gitSyncLocators.errorCallout).contains("Learn More").click(); + cy.get(gitSyncLocators.errorCallout).contains("Learn more").click(); cy.get(gitSyncLocators.closeGitSyncModal).click(); }); after(() => { - //cy.deleteTestGithubRepo(repoName); _.gitSync.DeleteTestGithubRepo(repoName); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js index 2f8069e6ac..689aa330d9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js @@ -1,52 +1,44 @@ import homePage from "../../../../../locators/HomePage"; import gitSyncLocators from "../../../../../locators/gitSyncLocators"; -import * as _ from "../../../../../support/Objects/ObjectsCore"; + +import { + agHelper, + entityExplorer, + homePage, + gitSync, +} from "../../../../../support/Objects/ObjectsCore"; let repoName, branchName; -// skipping this test as it gets stuck in CI, need to triage -describe.skip("Delete branch flow", () => { +describe("Delete branch flow", () => { it("1. Connect app to git, create new branch and delete it", () => { // create git repo and connect app to git - _.gitSync.CreateNConnectToGit(); + gitSync.CreateNConnectToGit(); cy.get("@gitRepoName").then((repName) => { repoName = repName; }); - _.gitSync.CreateGitBranch(); + gitSync.CreateGitBranch(); //cy.createGitBranch(branchName); cy.wait(1000); // verify can not delete the checked out branch - cy.get(gitSyncLocators.branchButton).click(); - cy.get(gitSyncLocators.branchListItem) - .eq(1) - .trigger("mouseenter") - .within(() => { - cy.get(gitSyncLocators.gitBranchContextMenu).click(); - cy.get(gitSyncLocators.gitBranchDelete).click(); - }); + DeleteBranchFromUI(1); cy.get("@gitbranchName").then((branName) => { branchName = branName; cy.get(homePage.toastMessage).should( "contain", `Cannot delete checked out branch. Please check out other branch before deleting ${branchName}.`, ); - cy.get(gitSyncLocators.closeBranchList).click(); + cy.get(gitSyncLocators.closeBranchList).click({ force: true }); // switch to master and delete new branch created cy.switchGitBranch("master"); cy.wait(2000); - cy.get(gitSyncLocators.branchButton).click(); - cy.get(gitSyncLocators.branchListItem) - .eq(1) - .trigger("mouseenter") - .within(() => { - cy.get(gitSyncLocators.gitBranchContextMenu).click(); - cy.get(gitSyncLocators.gitBranchDelete).click(); - }); + + DeleteBranchFromUI(1); cy.wait("@deleteBranch").should( "have.nested.property", "response.body.responseMeta.status", 200, ); - cy.get(gitSyncLocators.closeBranchList).click(); + cy.get(gitSyncLocators.closeBranchList).click({ force: true }); // verify remote branch is there for the deleted local branch cy.wait(2000); cy.switchGitBranch(`origin/${branchName}`); @@ -56,38 +48,33 @@ describe.skip("Delete branch flow", () => { it("2. Create child branch, merge data from child branch, delete child branch verify the data should reflect in master ", () => { cy.switchGitBranch("master"); - _.gitSync.CreateGitBranch("", true); + gitSync.CreateGitBranch("", true); cy.wait(1000); - _.entityExplorer.NavigateToSwitcher("Widgets"); + entityExplorer.NavigateToSwitcher("Widgets"); cy.dragAndDropToCanvas("checkboxwidget", { x: 100, y: 200 }); cy.get(".t--draggable-checkboxwidget").should("exist"); cy.wait(2000); cy.commitAndPush(); cy.merge("master"); - cy.get(".t--close-git-sync-modal").click(); + gitSync.CloseGitSyncModal(); cy.switchGitBranch("master"); cy.wait(2000); - cy.get(gitSyncLocators.branchButton).click(); - cy.get(gitSyncLocators.branchListItem) - .eq(1) - .trigger("mouseenter") - .within(() => { - cy.get(gitSyncLocators.gitBranchContextMenu).click(); - cy.get(gitSyncLocators.gitBranchDelete).click(); - }); + + DeleteBranchFromUI(1); + cy.wait("@deleteBranch").should( "have.nested.property", "response.body.responseMeta.status", 200, ); - cy.get(gitSyncLocators.closeBranchList).click(); + cy.get(gitSyncLocators.closeBranchList).click({ force: true }); cy.get(".t--draggable-checkboxwidget").should("be.visible"); }); it("3. Create new branch, commit data in that branch , delete the branch, verify data should not reflect in master ", () => { - _.gitSync.CreateGitBranch("", true); + gitSync.CreateGitBranch("", true); cy.wait(1000); - _.entityExplorer.NavigateToSwitcher("Widgets"); + entityExplorer.NavigateToSwitcher("Widgets"); cy.dragAndDropToCanvas("chartwidget", { x: 210, y: 300 }); cy.get(".t--widget-chartwidget").should("exist"); cy.wait(2000); @@ -95,40 +82,40 @@ describe.skip("Delete branch flow", () => { cy.wait(1000); cy.switchGitBranch("master"); cy.wait(3000); - cy.get(gitSyncLocators.branchButton).click(); - cy.get(gitSyncLocators.branchListItem) - .eq(1) - .trigger("mouseenter") - .within(() => { - cy.wait(1000); - cy.get(gitSyncLocators.gitBranchContextMenu).click(); - cy.wait(1000); - cy.get(gitSyncLocators.gitBranchDelete).click(); - }); + + DeleteBranchFromUI(1); + cy.wait("@deleteBranch").should( "have.nested.property", "response.body.responseMeta.status", 200, ); cy.get(".--widget-chartwidget").should("not.exist"); + cy.get(gitSyncLocators.closeBranchList).click({ force: true }); }); - /*it("4. Verify Default branch deletion not allowed ", () => { - cy.get(".t--branch-item") - .eq(0) - .click() + + it("4. Verify Default branch deletion not allowed ", () => { + agHelper.Sleep(2000); //for toasts to appear then wait for disappear + agHelper.WaitUntilAllToastsDisappear(); + DeleteBranchFromUI(0); + cy.get(gitSyncLocators.closeBranchList).click({ force: true }); + agHelper.ValidateToastMessage("Cannot delete default branch: master"); + }); + + function DeleteBranchFromUI(index = 1) { + cy.get(gitSyncLocators.branchButton).click(); + cy.get(gitSyncLocators.branchListItem) + .eq(index) .trigger("mouseenter") - .within(() => { - cy.get(".git-branch-more-menu").click({ force: true }); - cy.get(".t--branch-more-menu-delete").click(); - }); - cy.get(homePage.toastMessage).should( - "contain", - "Cannot delete default branch: master", - ); - }); */ + .wait(1000); + cy.get(gitSyncLocators.gitBranchContextMenu).click({ force: true }); + cy.xpath("//div[@role='menu']//span[text()='Delete']") + .should("be.visible") + .click({ force: true }); + } after(() => { //clean up - _.gitSync.DeleteTestGithubRepo(repoName); + gitSync.DeleteTestGithubRepo(repoName); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitBranchProtect_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitBranchProtect_spec.ts new file mode 100644 index 0000000000..91f342963c --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitBranchProtect_spec.ts @@ -0,0 +1,82 @@ +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; +import * as _ from "../../../../../support/Objects/ObjectsCore"; + +let guid: any; +let repoName1: any; +let repoName2: any; + +describe("Git Branch Protection", function () { + it("Issue 28056 - 1 : Check if protection is not enabled when feature flag is disabled", function () { + _.agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + guid = uid; + const wsName = "GitBranchProtect-1" + uid; + const appName = "GitBranchProtect-1" + uid; + _.homePage.CreateNewWorkspace(wsName, true); + _.homePage.CreateAppInWorkspace(wsName, appName); + featureFlagIntercept({ + release_git_connect_v2_enabled: true, + release_git_branch_protection_enabled: false, + }); + cy.wait(1000); + _.gitSync.CreateNConnectToGitV2(); + cy.get("@gitRepoName").then((repName) => { + repoName1 = repName; + _.agHelper.AssertElementExist(_.entityExplorer._entityExplorerWrapper); + _.agHelper.AssertElementExist(_.propPane._propertyPaneSidebar); + _.agHelper.AssertElementEnabledDisabled( + _.gitSync._bottomBarCommit, + 0, + false, + ); + }); + }); + }); + + it("Issue 28056 - 2 : Check if protection is enabled when feature flag is enabled", function () { + _.agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + guid = uid; + const wsName = "GitBranchProtect-2" + uid; + const appName = "GitBranchProtect-2" + uid; + _.homePage.CreateNewWorkspace(wsName, true); + _.homePage.CreateAppInWorkspace(wsName, appName); + featureFlagIntercept({ + release_git_connect_v2_enabled: true, + release_git_branch_protection_enabled: true, + }); + cy.wait(1000); + + cy.intercept({ + method: "POST", + url: /\/api\/v1\/git\/branch\/app\/.*\/protected/, + }).as("gitProtectApi"); + + _.gitSync.CreateNConnectToGitV2(); + cy.get("@gitRepoName").then((repName) => { + repoName2 = repName; + cy.wait("@gitProtectApi").then((res1) => { + expect(res1.response).to.have.property("statusCode", 200); + _.agHelper.AssertElementVisibility( + _.entityExplorer._entityExplorerWrapper, + false, + ); + _.agHelper.AssertElementVisibility( + _.propPane._propertyPaneSidebar, + false, + ); + _.agHelper.AssertElementEnabledDisabled( + _.gitSync._bottomBarCommit, + 0, + true, + ); + }); + }); + }); + }); + + after(() => { + _.gitSync.DeleteTestGithubRepo(repoName1); + _.gitSync.DeleteTestGithubRepo(repoName2); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitConnectV2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitConnectV2_spec.ts new file mode 100644 index 0000000000..79950ddb47 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitConnectV2_spec.ts @@ -0,0 +1,55 @@ +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; +import * as _ from "../../../../../support/Objects/ObjectsCore"; + +let ws1Name: string; +let ws2Name: string; +let app1Name: string; +let repoName: any; + +describe("Git Connect V2", function () { + before(() => { + _.agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + ws1Name = "GitConnectV2-1" + uid; + ws2Name = "GitConnectV2-2" + uid; + app1Name = "GitConnectV2" + uid; + _.homePage.CreateNewWorkspace(ws1Name, true); + _.homePage.CreateNewWorkspace(ws2Name, true); + _.homePage.CreateAppInWorkspace(ws1Name, app1Name); + }); + }); + + it("Testing connect to git flow - V2", function () { + featureFlagIntercept({ + release_git_connect_v2_enabled: true, + }); + + _.gitSync.CreateNConnectToGitV2(); + + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + }); + }); + + it("Testing import via git flow - V2", function () { + featureFlagIntercept({ + release_git_connect_v2_enabled: true, + }); + + _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 300, 300); + _.propPane.RenameWidget("Text1", "MyText"); + _.propPane.UpdatePropertyFieldValue("Text", "Hello World"); + _.gitSync.CommitAndPush(); + + _.gitSync.ImportAppFromGitV2(ws2Name, repoName); + + _.entityExplorer.ExpandCollapseEntity("Widgets"); + _.entityExplorer.AssertEntityPresenceInExplorer("MyText"); + _.entityExplorer.SelectEntityByName("MyText"); + _.propPane.ValidatePropertyFieldValue("Text", "Hello World"); + }); + + after(() => { + _.gitSync.DeleteTestGithubRepo(repoName); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitStatusLite_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitStatusLite_spec.ts new file mode 100644 index 0000000000..d2ed9ce35c --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitStatusLite_spec.ts @@ -0,0 +1,105 @@ +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; +import * as _ from "../../../../../support/Objects/ObjectsCore"; + +let wsName: string; +let appName: string; +let repoName: any; + +describe("Git Connect V2", function () { + before(() => { + _.agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + wsName = "GitStatusLite" + uid; + appName = "GitStatusLite" + uid; + _.homePage.CreateNewWorkspace(wsName, true); + _.homePage.CreateAppInWorkspace(wsName, appName); + _.gitSync.CreateNConnectToGit(); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + }); + }); + }); + + it("Issue 26038 - 1 : Simultaneous git status and remote compare api calls on commit modal", function () { + featureFlagIntercept({ + release_git_status_lite_enabled: true, + }); + + cy.wait(1000); + + cy.intercept({ + method: "GET", + url: "/api/v1/git/fetch/remote/app/**", + }).as("gitRemoteStatusApi"); + + cy.intercept({ + method: "GET", + url: "/api/v1/git/status/app/**", + query: { compareRemote: "false" }, + }).as("gitStatusApi"); + + _.agHelper.GetNClick(_.locators._publishButton); + + cy.wait("@gitRemoteStatusApi").then((res1) => { + expect(res1.response).to.have.property("statusCode", 200); + cy.wait("@gitStatusApi").then((res2) => { + expect(res2.response).to.have.property("statusCode", 200); + + _.agHelper.GetNClick(_.locators._dialogCloseButton); + }); + }); + }); + + it("Issue 26038 - 2 : Simultaneous git status and remote compare api calls on commit modal", function () { + featureFlagIntercept({ + release_git_status_lite_enabled: false, + }); + + cy.wait(1000); + + cy.intercept({ + method: "GET", + url: "/api/v1/git/status/app/**", + query: { compareRemote: "true" }, + }).as("gitStatusApi"); + + _.agHelper.GetNClick(_.locators._publishButton); + + cy.wait("@gitStatusApi").then((res1) => { + expect(res1.response).to.have.property("statusCode", 200); + _.agHelper.GetNClick(_.locators._dialogCloseButton); + }); + }); + + it("Issue 28462 : Simultaneous git status and remote compare api calls on canvas load", function () { + featureFlagIntercept({ + release_git_status_lite_enabled: true, + }); + + cy.wait(1000); + + cy.intercept({ + method: "GET", + url: "/api/v1/git/fetch/remote/app/**", + }).as("gitRemoteStatusApi"); + + cy.intercept({ + method: "GET", + url: "/api/v1/git/status/app/**", + query: { compareRemote: "false" }, + }).as("gitStatusApi"); + + cy.reload(); + + cy.wait("@gitRemoteStatusApi").then((res1) => { + expect(res1.response).to.have.property("statusCode", 200); + cy.wait("@gitStatusApi").then((res2) => { + expect(res2.response).to.have.property("statusCode", 200); + }); + }); + }); + + after(() => { + _.gitSync.DeleteTestGithubRepo(repoName); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js index a55f6cab6e..dd6490b6f0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncedApps_spec.js @@ -114,6 +114,7 @@ describe("Git sync apps", function () { 201, ); }); + it("2. Create api queries from api pane and cURL import , bind it to widget and clone page from page settings", () => { cy.fixture("datasources").then((datasourceFormData) => { cy.Createpage(newPage); @@ -277,6 +278,7 @@ describe("Git sync apps", function () { .should("be.oneOf", ["morpheus", "This is a test"]); deployMode.NavigateBacktoEditor(); }); + it("4. Create a new branch tempBranch, add jsObject and datasource query, move them to new page i.e. Child_Page and bind to widgets", () => { //cy.createGitBranch(tempBranch); gitSync.CreateGitBranch(tempBranch, true); @@ -342,6 +344,7 @@ describe("Git sync apps", function () { }); cy.wait(2000); }); + it("5. Commit and push changes, validate data binding on all pages in edit and deploy mode on tempBranch", () => { // commit and push changes cy.get(homePageLocators.publishButton).click(); @@ -439,6 +442,7 @@ describe("Git sync apps", function () { expect(cellData).to.be.equal("New Config"); }); */ }); + it("6. Switch to master and verify no uncommitted changes should be shown on master", () => { cy.switchGitBranch("master"); cy.wait(2000); @@ -449,6 +453,7 @@ describe("Git sync apps", function () { .and("have.text", "No changes to commit"); cy.get(gitSyncLocators.closeGitSyncModal).click(); }); + it("7. Switch to tempBranch , Clone the Child_Page, change it's visiblity to hidden and deploy, merge to master", () => { cy.switchGitBranch(tempBranch); cy.wait(2000); @@ -479,6 +484,7 @@ describe("Git sync apps", function () { agHelper.AssertContains("Child_Page Copy", "not.exist"); deployMode.NavigateBacktoEditor(); }); + it("8. Verify Page visiblity on master in edit and deploy mode", () => { cy.switchGitBranch(mainBranch); cy.wait(2000); @@ -486,6 +492,7 @@ describe("Git sync apps", function () { agHelper.AssertContains("Child_Page Copy", "not.exist"); deployMode.NavigateBacktoEditor(); }); + it("9. Create new branch, delete a page and merge back to master, verify page is deleted on master", () => { //cy.createGitBranch(tempBranch1); gitSync.CreateGitBranch(tempBranch1, true); @@ -508,6 +515,7 @@ describe("Git sync apps", function () { cy.CheckAndUnfoldEntityItem("Pages"); cy.get(`.t--entity-name:contains("Child_Page Copy")`).should("not.exist"); }); + it("10. Import app from git and verify page order should not change", () => { cy.get(homePageLocators.homeIcon).click(); cy.get(homePageLocators.optionsIcon).first().click(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/LearnMore_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/LearnMore_spec.ts new file mode 100644 index 0000000000..f73e9900f8 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/LearnMore_spec.ts @@ -0,0 +1,74 @@ +import gitSyncLocators from "../../../../../locators/gitSyncLocators"; +import homePage from "../../../../../locators/HomePage"; +import * as _ from "../../../../../support/Objects/ObjectsCore"; + +const httpsRepoURL = "https://github.com/test/test.git"; +const invalidURL = "test"; + +let repoName: string; +let generatedKey; +let windowOpenSpy: any; +describe("Git sync modal: Learn more links", function () { + it("1. validates repo URL", function () { + // open gitSync modal + cy.get(homePage.deployPopupOptionTrigger).click({ force: true }); + cy.get(homePage.connectToGitBtn).click({ force: true }); + + cy.get(gitSyncLocators.gitRepoInput).type(`{selectAll}${httpsRepoURL}`); + cy.contains(Cypress.env("MESSAGES").PASTE_SSH_URL_INFO()); + cy.get(gitSyncLocators.generateDeployKeyBtn).should("not.exist"); + + cy.get(gitSyncLocators.gitRepoInput).type(`{selectAll}${invalidURL}`); + cy.contains(Cypress.env("MESSAGES").PASTE_SSH_URL_INFO()); + cy.get(gitSyncLocators.generateDeployKeyBtn).should("not.exist"); + + // generate key button should be disappeared if empty repo + cy.get(gitSyncLocators.gitRepoInput).type(`{selectAll}${""}`); + cy.get(gitSyncLocators.generateDeployKeyBtn).should("not.exist"); + + cy.get(gitSyncLocators.gitRepoInput).type( + `{selectAll}${_.dataManager.GITEA_API_URL_TED}/${repoName}.git`, + ); + cy.contains(Cypress.env("MESSAGES").PASTE_SSH_URL_INFO()).should( + "not.exist", + ); + + cy.get(gitSyncLocators.generateDeployKeyBtn).should("not.be.disabled"); + + cy.intercept("POST", "/api/v1/applications/ssh-keypair/*").as( + "generateKey", + ); + + // Stubbing window.open + // cy.window().then((window) => { + // windowOpenSpy = cy.stub(window, "open").callsFake((url) => { + // expect(url.startsWith("https://docs.appsmith.com/")).to.be.true; + // windowOpenSpy.restore(); + // }); + // }); + + cy.window().then((window) => { + windowOpenSpy = cy.stub(window, "open").callsFake((url) => { + if ( + url.includes("/version-control-with-git/connecting-to-git-repository") + ) { + expect(url).to.contain( + "/version-control-with-git/connecting-to-git-repository", + ); + } else if (url.includes("overview/managing-deploy-keys")) { + expect(url).to.contain("overview/managing-deploy-keys"); + } + windowOpenSpy.restore(); + }); + }); + + // Click the "Learn more" link + cy.get(gitSyncLocators.learnMoreSshUrl).click(); + cy.get(gitSyncLocators.generateDeployKeyBtn).click(); + + cy.wait("@generateKey").then((result: any) => { + generatedKey = result.response.body.data.publicKey; + }); + cy.xpath(gitSyncLocators.learnMoreDeployKey).click({ force: true }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Git_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/MergeViaRemote_spec.ts similarity index 79% rename from app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Git_spec.js rename to app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/MergeViaRemote_spec.ts index 246de7ec08..f424d86f6e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Git_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/MergeViaRemote_spec.ts @@ -1,6 +1,5 @@ -const widgetsPage = require("../../../../../locators/Widgets.json"); -const commonlocators = require("../../../../../locators/commonlocators.json"); -const explorerLocators = require("../../../../../locators/explorerlocators.json"); +import widgetsPage from "../../../../../locators/Widgets.json"; +import commonlocators from "../../../../../locators/commonlocators.json"; import gitSyncLocators from "../../../../../locators/gitSyncLocators"; import homePage from "../../../../../locators/HomePage"; import * as _ from "../../../../../support/Objects/ObjectsCore"; @@ -22,37 +21,32 @@ const inputNameTempBranch31 = "inputNameTempBranch31"; const cleanUrlBranch = "feat/clean_url"; -let applicationId = null; -let applicationName = null; +let applicationId: any; +let applicationName: any; +let repoName: any; -let repoName; -describe.skip("Git sync:", function () { +describe("Git sync: Merge changes via remote", function () { before(() => { _.homePage.NavigateToHome(); - cy.createWorkspace(); - cy.wait("@createWorkspace").then((interception) => { - const newWorkspaceName = interception.response.body.data.name; - cy.generateUUID().then((uid) => { - cy.CreateAppForWorkspace(newWorkspaceName, uid); + _.homePage.CreateNewWorkspace(); + + _.agHelper.GenerateUUID(); + cy.get("@guid").then((uid: any) => { + cy.get("@workspaceName").then((workspaceName: any) => { + _.homePage.CreateAppInWorkspace(workspaceName, uid); applicationName = uid; - cy.get("@currentApplicationId").then( + cy.get("@applicationId").then( (currentAppId) => (applicationId = currentAppId), ); }); }); - - // cy.generateUUID().then((uid) => { - // repoName = uid; _.gitSync.CreateNConnectToGit(repoName); - // cy.createTestGithubRepo(repoName); - // cy.connectToGitRepo(repoName); - //}); cy.get("@gitRepoName").then((repName) => { repoName = repName; }); }); - it("1. Shows remote is ahead warning and conflict error during commit and push", function () { + it.skip("1. Shows remote is ahead warning and conflict error during commit and push", function () { _.gitSync.CreateGitBranch(tempBranch, false); cy.get("@gitbranchName").then((branName) => { tempBranch = branName; @@ -104,7 +98,7 @@ describe.skip("Git sync:", function () { cy.get(gitSyncLocators.closeGitSyncModal).click(); }); - it("2. Detect conflicts when merging head to base branch", function () { + it.skip("2. Detect conflicts when merging head to base branch", function () { cy.switchGitBranch(mainBranch); _.entityExplorer.NavigateToSwitcher("Widgets"); cy.wait(2000); // wait for transition @@ -137,7 +131,7 @@ describe.skip("Git sync:", function () { }); it("3. Supports merging head to base branch", function () { - cy.switchGitBranch(mainBranch); + //cy.switchGitBranch(mainBranch); cy.createGitBranch(tempBranch2); _.entityExplorer.NavigateToSwitcher("Explorer"); cy.CheckAndUnfoldEntityItem("Pages"); @@ -145,13 +139,13 @@ describe.skip("Git sync:", function () { cy.commitAndPush(); cy.merge(mainBranch); cy.get(gitSyncLocators.closeGitSyncModal).click(); - cy.wait(8000); + cy.wait(4000); cy.switchGitBranch(mainBranch); cy.wait(4000); // wait for switch branch cy.contains("NewPage"); }); - it("4. Enables pulling remote changes from bottom bar", function () { + it.skip("4. Enables pulling remote changes from bottom bar", function () { _.gitSync.CreateGitBranch(tempBranch3, false); _.entityExplorer.NavigateToSwitcher("Widgets"); cy.wait(2000); // wait for transition @@ -234,7 +228,6 @@ describe.skip("Git sync:", function () { req.continue(); }).as("appAndPages"); cy.reload(); - //cy.pause(); cy.wait("@appAndPages").then((intercept2) => { const { application, pages } = intercept2.response.body.data; const defaultPage = pages.find((p) => p.isDefault); @@ -250,7 +243,7 @@ describe.skip("Git sync:", function () { applicationVersion: 1, }); - _.gitSync.CreateGitBranch(cleanUrlBranch, false); + _.gitSync.CreateGitBranch(cleanUrlBranch, true); cy.location().should((location) => { expect(location.pathname).includes(legacyPathname); @@ -266,33 +259,33 @@ describe.skip("Git sync:", function () { expect(location.pathname).includes(newPathname); }); - _.gitSync.CreateGitBranch(cleanUrlBranch, false); + _.gitSync.CreateGitBranch(cleanUrlBranch, false, false); //false is sent for assertCreateBranch since here it only goes to the branch already created cy.location().should((location) => { expect(location.pathname).includes(legacyPathname); }); }); - after(() => { - // _.gitSync.DeleteTestGithubRepo(repoName); - // //cy.deleteTestGithubRepo(repoName); - // // TODO remove when app deletion with conflicts is fixed - // cy.get(homePage.homeIcon).click({ force: true }); - // cy.get(homePage.createNew) - // .first() - // .click({ force: true }); - // cy.wait("@createNewApplication").should( - // "have.nested.property", - // "response.body.responseMeta.status", - // 201, - // ); - // cy.get("#loading").should("not.exist"); - // cy.wait(2000); - // cy.AppSetupForRename(); - // cy.get(homePage.applicationName).type(repoName + "{enter}"); - // cy.wait("@updateApplication").should( - // "have.nested.property", - // "response.body.responseMeta.status", - // 200, - // ); - }); + // after(() => { + // // _.gitSync.DeleteTestGithubRepo(repoName); + // // //cy.deleteTestGithubRepo(repoName); + // // // TODO remove when app deletion with conflicts is fixed + // // cy.get(homePage.homeIcon).click({ force: true }); + // // cy.get(homePage.createNew) + // // .first() + // // .click({ force: true }); + // // cy.wait("@createNewApplication").should( + // // "have.nested.property", + // // "response.body.responseMeta.status", + // // 201, + // // ); + // // cy.get("#loading").should("not.exist"); + // // cy.wait(2000); + // // cy.AppSetupForRename(); + // // cy.get(homePage.applicationName).type(repoName + "{enter}"); + // // cy.wait("@updateApplication").should( + // // "have.nested.property", + // // "response.body.responseMeta.status", + // // 200, + // // ); + // }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/RepoLimitExceededErrorModal_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/RepoLimitExceededErrorModal_spec.js index 0b65860f6e..1ef022b335 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/RepoLimitExceededErrorModal_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/RepoLimitExceededErrorModal_spec.js @@ -1,53 +1,55 @@ import gitSyncLocators from "../../../../../locators/gitSyncLocators"; -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + gitSync, + agHelper, + homePage, + onboarding, + locators, +} from "../../../../../support/Objects/ObjectsCore"; import { REPO, CURRENT_REPO } from "../../../../../fixtures/REPO"; let repoName1, repoName2, repoName3, repoName4, windowOpenSpy; describe("Repo Limit Exceeded Error Modal", function () { before(() => { - cy.generateUUID().then((uid) => { - cy.Signup(`${uid}@appsmithtest.com`, uid); - }); const uuid = require("uuid"); repoName1 = uuid.v4().split("-")[0]; repoName2 = uuid.v4().split("-")[0]; repoName3 = uuid.v4().split("-")[0]; repoName4 = uuid.v4().split("-")[0]; - _.agHelper.AssertElementVisibility(_.locators._sidebar); - _.onboarding.closeIntroModal(); + agHelper.AssertElementVisibility(locators._sidebar); + onboarding.closeIntroModal(); }); - it("1. Modal should be opened with proper components", function () { - _.homePage.NavigateToHome(); - _.homePage.CreateNewApplication(); - _.gitSync.CreateNConnectToGit(repoName1, true, true); + it("1. Verify Repo limit flow for CE instance", function () { + agHelper.Sleep(2000); // adding wait for app to load + homePage.LogOutviaAPI(); + cy.generateUUID().then((uid) => { + cy.Signup(`${uid}@appsmithtest.com`, uid); + }); + homePage.NavigateToHome(); + homePage.CreateNewApplication(); + gitSync.CreateNConnectToGit(repoName1, true, true); cy.get("@gitRepoName").then((repName) => { repoName1 = repName; }); - _.homePage.NavigateToHome(); - _.homePage.CreateNewApplication(); - _.gitSync.CreateNConnectToGit(repoName2, true, true); + homePage.NavigateToHome(); + homePage.CreateNewApplication(); + gitSync.CreateNConnectToGit(repoName2, true, true); cy.get("@gitRepoName").then((repName) => { repoName2 = repName; }); - _.homePage.NavigateToHome(); - _.homePage.CreateNewApplication(); - _.gitSync.CreateNConnectToGit(repoName3, true, true); + homePage.NavigateToHome(); + homePage.CreateNewApplication(); + gitSync.CreateNConnectToGit(repoName3, true, true); cy.get("@gitRepoName").then((repName) => { repoName3 = repName; }); - _.homePage.NavigateToHome(); - _.homePage.CreateNewApplication(); - _.gitSync.CreateNConnectToGit(repoName4, false, true); + homePage.NavigateToHome(); + homePage.CreateNewApplication(); + gitSync.CreateNConnectToGit(repoName4, false, true); cy.get("@gitRepoName").then((repName) => { repoName4 = repName; }); - - // cy.createAppAndConnectGit(repoName1, false); - // cy.createAppAndConnectGit(repoName2, false); - // cy.createAppAndConnectGit(repoName3, false); - // cy.createAppAndConnectGit(repoName4, false, true); - if (CURRENT_REPO === REPO.CE) { cy.get(gitSyncLocators.repoLimitExceededErrorModal).should("exist"); @@ -63,7 +65,7 @@ describe("Repo Limit Exceeded Error Modal", function () { ); cy.get(gitSyncLocators.gitModalLink).should( "contain.text", - "Contact Support", + "Contact support", ); cy.get(gitSyncLocators.repoLimitExceededErrorModal).contains( Cypress.env("MESSAGES").REVOKE_CAUSE_APPLICATION_BREAK(), @@ -90,29 +92,13 @@ describe("Repo Limit Exceeded Error Modal", function () { }); after(() => { - cy.request({ - method: "DELETE", - url: "api/v1/applications/" + repoName1, - failOnStatusCode: false, - }); - cy.request({ - method: "DELETE", - url: "api/v1/applications/" + repoName2, - failOnStatusCode: false, - }); - cy.request({ - method: "DELETE", - url: "api/v1/applications/" + repoName3, - failOnStatusCode: false, - }); - cy.request({ - method: "DELETE", - url: "api/v1/applications/" + repoName4, - failOnStatusCode: false, - }); - _.gitSync.DeleteTestGithubRepo(repoName1); - _.gitSync.DeleteTestGithubRepo(repoName2); - _.gitSync.DeleteTestGithubRepo(repoName3); - _.gitSync.DeleteTestGithubRepo(repoName4); + homePage.DeleteAppviaAPI(repoName1); + homePage.DeleteAppviaAPI(repoName2); + homePage.DeleteAppviaAPI(repoName3); + homePage.DeleteAppviaAPI(repoName4); + gitSync.DeleteTestGithubRepo(repoName1); + gitSync.DeleteTestGithubRepo(repoName2); + gitSync.DeleteTestGithubRepo(repoName3); + gitSync.DeleteTestGithubRepo(repoName4); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js index 64adbb88c3..4a82a357c0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js @@ -1,6 +1,12 @@ import HomePage from "../../../../../locators/HomePage"; import gitSyncLocators from "../../../../../locators/gitSyncLocators"; -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + entityExplorer, + homePage, + gitSync, + installer, +} from "../../../../../support/Objects/ObjectsCore"; const mainBranch = "master"; const tempBranch = "feat/tempBranch"; @@ -8,48 +14,49 @@ let repoName; describe("excludeForAirgap", "Tests JS Library with Git", () => { before(() => { - _.homePage.NavigateToHome(); + homePage.NavigateToHome(); cy.createWorkspace(); cy.wait("@createWorkspace").then((interception) => { const newWorkspaceName = interception.response.body.data.name; cy.CreateAppForWorkspace(newWorkspaceName, newWorkspaceName); }); // connect app to git - _.gitSync.CreateNConnectToGit(repoName); + gitSync.CreateNConnectToGit(repoName); cy.get("@gitRepoName").then((repName) => { repoName = repName; }); }); it("1. Install JS Library and commit changes, create branch and verify JS library changes are present on new branch ", () => { - _.entityExplorer.ExpandCollapseEntity("Libraries"); - _.installer.OpenInstaller(); - _.installer.installLibrary("uuidjs", "UUID"); - cy.commitAndPush(); + entityExplorer.ExpandCollapseEntity("Libraries"); + installer.OpenInstaller(); + installer.InstallLibrary("uuidjs", "UUID"); + gitSync.CommitAndPush(); // create new branch - _.gitSync.CreateGitBranch(tempBranch, true); + gitSync.CreateGitBranch(tempBranch, true); // verify js library changes are present - _.entityExplorer.ExpandCollapseEntity("Libraries"); - _.installer.AssertLibraryinExplorer("uuidjs"); + entityExplorer.ExpandCollapseEntity("Libraries"); + installer.AssertLibraryinExplorer("uuidjs"); }); + it("2. Discard custom js library changes, verify changes are discarded also verify it deosnt show uncommitted changes", () => { - _.entityExplorer.ExpandCollapseEntity("Libraries"); - _.installer.uninstallLibrary("uuidjs"); - _.installer.assertUnInstall("uuidjs"); + entityExplorer.ExpandCollapseEntity("Libraries"); + installer.uninstallLibrary("uuidjs"); + installer.assertUnInstall("uuidjs"); // discard js library uninstallation cy.gitDiscardChanges(); // verify js library is present - _.entityExplorer.ExpandCollapseEntity("Libraries"); - _.installer.AssertLibraryinExplorer("uuidjs"); + entityExplorer.ExpandCollapseEntity("Libraries"); + installer.AssertLibraryinExplorer("uuidjs"); // verify no uncommitted changes are there - _.agHelper.AssertElementExist(_.gitSync._bottomBarPull); + agHelper.AssertElementExist(gitSync._bottomBarPull); cy.get(gitSyncLocators.bottomBarCommitButton).click(); cy.get(gitSyncLocators.commitCommentInput).should("be.disabled"); cy.get(gitSyncLocators.commitButton).should("be.disabled"); cy.get(gitSyncLocators.closeGitSyncModal).click(); // swtich to master, verify no uncommitted changes cy.switchGitBranch("master"); - _.agHelper.AssertElementExist(_.gitSync._bottomBarPull); + agHelper.AssertElementExist(gitSync._bottomBarPull); cy.get(gitSyncLocators.bottomBarCommitButton).click(); cy.get(gitSyncLocators.commitCommentInput).should("be.disabled"); cy.get(gitSyncLocators.commitButton).should("be.disabled"); @@ -58,17 +65,17 @@ describe("excludeForAirgap", "Tests JS Library with Git", () => { it("3. Merge custom js lib changes from child branch to master, verify changes are merged", () => { cy.switchGitBranch(tempBranch); - _.agHelper.AssertElementExist(_.gitSync._bottomBarPull); - _.entityExplorer.ExpandCollapseEntity("Libraries"); - _.installer.OpenInstaller(); - _.installer.installLibrary("jspdf", "jspdf"); + agHelper.AssertElementExist(gitSync._bottomBarPull); + entityExplorer.ExpandCollapseEntity("Libraries"); + installer.OpenInstaller(); + installer.InstallLibrary("jspdf", "jspdf"); //cy.commitAndPush(); cy.get(HomePage.publishButton).click(); - _.agHelper.AssertElementExist(_.gitSync._bottomBarPull); + agHelper.AssertElementExist(gitSync._bottomBarPull); cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); cy.get(gitSyncLocators.commitButton).click(); - _.agHelper.AssertElementExist(_.gitSync._bottomBarPull); + agHelper.AssertElementExist(gitSync._bottomBarPull); cy.get(gitSyncLocators.closeGitSyncModal).click(); cy.wait(2000); cy.merge(mainBranch); @@ -76,12 +83,12 @@ describe("excludeForAirgap", "Tests JS Library with Git", () => { cy.wait(2000); // verify custom js library is present in master branch cy.switchGitBranch(mainBranch); - _.agHelper.AssertElementExist(_.gitSync._bottomBarPull); - _.entityExplorer.ExpandCollapseEntity("Libraries"); - _.installer.AssertLibraryinExplorer("jspdf"); + agHelper.AssertElementExist(gitSync._bottomBarPull); + entityExplorer.ExpandCollapseEntity("Libraries"); + installer.AssertLibraryinExplorer("jspdf"); }); after(() => { //clean up - _.gitSync.DeleteTestGithubRepo(repoName); + gitSync.DeleteTestGithubRepo(repoName); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js index 451f815aa2..5547854f42 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js @@ -3,7 +3,7 @@ const widgetsPage = require("../../../../../locators/Widgets.json"); const commonlocators = require("../../../../../locators/commonlocators.json"); describe("Git with Theming:", function () { - const backgroudColorMaster = "rgb(85, 61, 233)"; + const backgroudColorMaster = "rgb(22, 163, 74)"; const backgroudColorChildBranch = "rgb(100, 116, 139)"; const tempBranch = "tempBranch"; let repoName; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Google/EnableGoogle_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Google/EnableGoogle_spec.js index 699c516e26..9f9947103a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Google/EnableGoogle_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Google/EnableGoogle_spec.js @@ -27,7 +27,7 @@ describe("excludeForAirgap", "SSO with Google test functionality", function () { }); it("2. Go to admin settings and enable Google", function () { - cy.LogOut(); + cy.LogOut(false); cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); cy.get(".admin-settings-menu-option").should("be.visible"); cy.get(".admin-settings-menu-option").click(); @@ -64,7 +64,7 @@ describe("excludeForAirgap", "SSO with Google test functionality", function () { }); it("3. Go to admin settings and disable Google", function () { - cy.LogOut(); + cy.LogOut(false); cy.LoginFromAPI(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); cy.get(".admin-settings-menu-option").should("be.visible"); cy.get(".admin-settings-menu-option").click(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/IDE/Canvas_Context_Selected_Widgets_spec.js b/app/client/cypress/e2e/Regression/ClientSide/IDE/Canvas_Context_Selected_Widgets_spec.js index 01f5416bd7..afe47d3a16 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/IDE/Canvas_Context_Selected_Widgets_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/IDE/Canvas_Context_Selected_Widgets_spec.js @@ -272,4 +272,40 @@ describe("Canvas context widget selection", function () { cy.get(".is-selected").should("contain", "Tab 2"); cy.get(".t--property-pane-title").should("contain", "Button4"); }); + + it("11. Widgets inside modal widget should open when loaded from the URL", function () { + //select widget in page1 + _.entityExplorer.SelectEntityInModal("Modal1", "Widgets"); + + //verify the Modal1 is open and Text1 is selected in page1 + cy.get(`div[data-testid='t--selected']`).should("have.length", 1); + cy.get(".t--modal-widget").should("have.length", 1); + cy.get(".t--property-pane-title").should("contain", "Text1"); + + // Get the current URL + cy.url().then((url) => { + //switch to page2 + _.entityExplorer.SelectEntityByName(page2, "Pages"); + + //select widget in page2 + _.entityExplorer.SelectEntityByName("Text1", "Widgets"); + + //verify the widget is selected in page2 + cy.get(`div[data-testid='t--selected']`).should("have.length", 1); + + // open the URL + cy.visit(url); + + // wati for the page to load + cy.wait(4000); + + //select widget in page1 + _.entityExplorer.SelectEntityInModal("Modal1", "Widgets"); + + //verify the Modal1 is open and Text1 is selected in page1 + cy.get(`div[data-testid='t--selected']`).should("have.length", 1); + cy.get(".t--modal-widget").should("have.length", 1); + cy.get(".t--property-pane-title").should("contain", "Text1"); + }); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/IDE/Command_Click_Navigation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/IDE/Command_Click_Navigation_spec.js index 3813ead278..b0827df668 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/IDE/Command_Click_Navigation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/IDE/Command_Click_Navigation_spec.js @@ -1,6 +1,12 @@ import reconnectDatasourceModal from "../../../../locators/ReconnectLocators"; import { PROPERTY_SELECTOR } from "../../../../locators/WidgetLocators"; -import * as _ from "../../../../support/Objects/ObjectsCore"; +import { + agHelper, + homePage, + entityExplorer, + locators, + gitSync, +} from "../../../../support/Objects/ObjectsCore"; const NAVIGATION_ATTRIBUTE = "data-navigate-to"; @@ -24,28 +30,28 @@ let repoName; describe("1. CommandClickNavigation", function () { it("1. Import application & Assert few things", () => { - _.homePage.NavigateToHome(); + homePage.NavigateToHome(); cy.reload(); - _.homePage.ImportApp("ContextSwitching.json"); + homePage.ImportApp("ContextSwitching.json"); cy.wait("@importNewApplication").then((interception) => { - _.agHelper.Sleep(); + agHelper.Sleep(); const { isPartialImport } = interception.response.body.data; if (isPartialImport) { // should reconnect modal cy.get(reconnectDatasourceModal.SkipToAppBtn).click({ force: true, }); - _.agHelper.Sleep(2000); + agHelper.Sleep(2000); } else { - _.homePage.AssertImportToast(); + homePage.AssertImportToast(); } }); }); it("2. Assert link and and style", () => { cy.CheckAndUnfoldEntityItem("Queries/JS"); - _.entityExplorer.ExpandCollapseEntity("Widgets"); - _.entityExplorer.SelectEntityByName("Text1", "Container1"); + entityExplorer.ExpandCollapseEntity("Widgets"); + entityExplorer.SelectEntityByName("Text1", "Container1"); cy.updateCodeInput(".t--property-control-text", "{{ Graphql_Query.data }}"); @@ -59,7 +65,7 @@ describe("1. CommandClickNavigation", function () { // Assert navigation only when cmd or ctrl is pressed - _.agHelper.Sleep(); + agHelper.Sleep(); cy.get(`[${NAVIGATION_ATTRIBUTE}="Graphql_Query"]`).click({ force: true }); cy.url().should("not.contain", "/api/"); @@ -76,7 +82,7 @@ describe("1. CommandClickNavigation", function () { ".t--dataSourceField", "https://www.test.com/{{ SQL_Query.data }}", ); - _.agHelper.Sleep(); + agHelper.Sleep(); cy.get(`[${NAVIGATION_ATTRIBUTE}="SQL_Query"]`) .should("have.length", 1) @@ -90,7 +96,7 @@ describe("1. CommandClickNavigation", function () { ".t--actionConfiguration\\.body", "SELECT * from {{ Button3.text }}", ); - _.agHelper.Sleep(); + agHelper.Sleep(); cy.get(`[${NAVIGATION_ATTRIBUTE}="Button3"]`) .should("have.length", 1) .click({ cmdKey: true }); @@ -100,7 +106,7 @@ describe("1. CommandClickNavigation", function () { it("6. Will close modals", () => { cy.updateCodeInput( - `${_.locators._propertyControl}tooltip`, + `${locators._propertyControl}tooltip`, "{{ Image1.image }}", ); @@ -115,19 +121,19 @@ describe("1. CommandClickNavigation", function () { // cmd clicking to JS function reloaded the app. Will assert that does not happen cy.generateUUID().then((uid) => { const repoName = uid; - _.gitSync.CreateNConnectToGit(repoName); - _.gitSync.CreateGitBranch(repoName); + gitSync.CreateNConnectToGit(repoName); + gitSync.CreateGitBranch(repoName); }); cy.get("@gitRepoName").then((repName) => { repoName = repName; }); - _.entityExplorer.ExpandCollapseEntity("Widgets"); - _.entityExplorer.SelectEntityByName("Text1", "Container1"); + entityExplorer.ExpandCollapseEntity("Widgets"); + entityExplorer.SelectEntityByName("Text1", "Container1"); cy.updateCodeInput(".t--property-control-text", "{{ JSObject1.myFun1() }}"); - _.agHelper.Sleep(); + agHelper.Sleep(); cy.get(`[${NAVIGATION_ATTRIBUTE}="JSObject1.myFun1"]`).click({ cmdKey: true, @@ -135,10 +141,10 @@ describe("1. CommandClickNavigation", function () { }); cy.assertCursorOnCodeInput(".js-editor", { ch: 1, line: 3 }); - _.agHelper.Sleep(); + agHelper.Sleep(); // Assert context switching works when going back to canvas - _.entityExplorer.SelectEntityByName("Page1", "Pages"); + entityExplorer.SelectEntityByName("Page1", "Pages"); cy.get(`div[data-testid='t--selected']`).should("have.length", 1); cy.get(".t--property-pane-title").should("contain", "Text1"); @@ -151,7 +157,7 @@ describe("1. CommandClickNavigation", function () { it("8. Will navigate within Js Object properly", () => { cy.updateCodeInput(".js-editor", JSInputTestCode); - _.agHelper.Sleep(2000); + agHelper.Sleep(2000); cy.get(`[${NAVIGATION_ATTRIBUTE}="JSObject1.myVar1"]`).click({ ctrlKey: true, }); @@ -160,7 +166,7 @@ describe("1. CommandClickNavigation", function () { codeMirrorInput.focus(); }); cy.assertCursorOnCodeInput(".js-editor", { ch: 2, line: 1 }); - _.agHelper.Sleep(); + agHelper.Sleep(); cy.get(`[${NAVIGATION_ATTRIBUTE}="JSObject1.myFun1"]`).click({ ctrlKey: true, }); @@ -170,7 +176,7 @@ describe("1. CommandClickNavigation", function () { }); cy.assertCursorOnCodeInput(".js-editor", { ch: 2, line: 2 }); - _.agHelper.Sleep(); + agHelper.Sleep(); cy.get(`[${NAVIGATION_ATTRIBUTE}="JSObject2.myFun1"]`).click({ ctrlKey: true, }); @@ -181,20 +187,23 @@ describe("1. CommandClickNavigation", function () { }); }); - it.skip("Will work with string arguments in framework functions", () => { - cy.get(PROPERTY_SELECTOR.onClick).find(".t--js-toggle").click(); - cy.updateCodeInput( - PROPERTY_SELECTOR.onClick, - "{{ resetWidget('Input1') }}", - ); - _.agHelper.Sleep(); - cy.get(`[${NAVIGATION_ATTRIBUTE}="Input1"]`) - .should("have.length", 1) - .click({ cmdKey: true }); - }); + // Functionality isn't implemented yet + // it("5. Will work with string arguments in framework functions", () => { + // entityExplorer.ExpandCollapseEntity("Widgets"); + // entityExplorer.SelectEntityByName("Button1", "Container1"); + // cy.get(PROPERTY_SELECTOR.onClick).find(".t--js-toggle").click(); + // cy.updateCodeInput( + // PROPERTY_SELECTOR.onClick, + // "{{ resetWidget('Input1') }}", + // ); + // agHelper.Sleep(); + // cy.get(`[${NAVIGATION_ATTRIBUTE}="Input1"]`) + // .should("have.length", 1) + // .click({ cmdKey: true }); + // }); after(() => { //clean up - _.gitSync.DeleteTestGithubRepo(repoName); + gitSync.DeleteTestGithubRepo(repoName); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/IDE/MaintainContext&Focus_spec.js b/app/client/cypress/e2e/Regression/ClientSide/IDE/MaintainContext&Focus_spec.js index 9e87bc798a..794973a024 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/IDE/MaintainContext&Focus_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/IDE/MaintainContext&Focus_spec.js @@ -13,17 +13,18 @@ const queryLocators = require("../../../../locators/QueryEditor.json"); describe("MaintainContext&Focus", function () { before("Import the test application", () => { - homePage.NavigateToHome(); + homePage.CreateNewWorkspace("MaintainContext&Focus", true); homePage.ImportApp("ContextSwitching.json"); cy.wait("@importNewApplication").then((interception) => { _.agHelper.Sleep(); const { isPartialImport } = interception.response.body.data; + cy.log("isPartialImport is", isPartialImport); if (isPartialImport) { // should reconnect modal cy.get("body").then(($ele) => { if ($ele.find(reconnectDatasourceModal.SkipToAppBtn)) agHelper.GetNClick(reconnectDatasourceModal.SkipToAppBtn, 0, true); - else agHelper.GetNClick(homePage._importSuccessModalGotit, 0, true); + else agHelper.ClickButton("Got it"); agHelper.Sleep(2000); }); } else { @@ -214,7 +215,7 @@ describe("MaintainContext&Focus", function () { cy.assertCursorOnCodeInput(".js-editor", { ch: 2, line: 4 }); cy.get(locators._codeMirrorTextArea).type("showA"); - agHelper.GetNAssertElementText(locators._hints, "showAlert()"); + agHelper.GetNAssertElementText(locators._hints, "showAlert"); agHelper.PressEscape(); cy.assertCursorOnCodeInput(".js-editor", { ch: 7, line: 4 }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/JSLibrary/Library_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/JSLibrary/Library_spec.ts index 4dcfb009cf..b86b9bf19e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/JSLibrary/Library_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/JSLibrary/Library_spec.ts @@ -5,25 +5,24 @@ describe("excludeForAirgap", "Tests JS Libraries", () => { it("1. Validates Library install/uninstall", () => { _.entityExplorer.ExpandCollapseEntity("Libraries"); _.installer.OpenInstaller(); - _.installer.installLibrary("uuidjs", "UUID"); + _.installer.InstallLibrary("uuidjs", "UUID"); _.installer.uninstallLibrary("uuidjs"); _.installer.assertUnInstall("uuidjs"); }); - it("2. Checks for naming collision", () => { + it("2. Installs the library against a unique namespace when there is a collision with the existing entity", () => { _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TABLE, 200, 200); _.entityExplorer.NavigateToSwitcher("Explorer"); _.entityExplorer.RenameEntityFromExplorer("Table1", "jsonwebtoken"); _.entityExplorer.ExpandCollapseEntity("Libraries"); _.installer.OpenInstaller(); - _.installer.installLibrary("jsonwebtoken", "jsonwebtoken", false); - _.agHelper.AssertContains("Name collision detected: jsonwebtoken"); + _.installer.InstallLibrary("jsonwebtoken", "jsonwebtoken_1", true); }); it("3. Checks jspdf library", () => { _.entityExplorer.ExpandCollapseEntity("Libraries"); _.installer.OpenInstaller(); - _.installer.installLibrary("jspdf", "jspdf"); + _.installer.InstallLibrary("jspdf", "jspdf"); _.jsEditor.CreateJSObject( `export default { myFun1: () => { @@ -45,7 +44,28 @@ describe("excludeForAirgap", "Tests JS Libraries", () => { _.debuggerHelper.ClickResponseTab(); _.agHelper.AssertContains("data:application/pdf;filename=generated.pdf"); }); - it("4. Shows list of recommended libraries", () => { + + it("4. ESM build should pass installation, uninstallation and reinstallation", () => { + _.entityExplorer.ExpandCollapseEntity("Libraries"); + _.installer.OpenInstaller(); + _.installer.InstallLibraryViaURL( + "https://cdn.jsdelivr.net/npm/fast-xml-parser@4.2.7/+esm", + "fast_xml_parser", + ); + _.agHelper.Sleep(2000); + // Uninstallation should succeed + _.installer.uninstallLibrary("fast_xml_parser"); + _.installer.assertUnInstall("fast_xml_parser"); + + // Reinstallation should succeed with the same accessor + _.installer.OpenInstaller(); + _.installer.InstallLibraryViaURL( + "https://cdn.jsdelivr.net/npm/fast-xml-parser@4.2.7/+esm", + "fast_xml_parser", + ); + }); + + it("5. Shows list of recommended libraries", () => { const recommendedLibraryNames = ["jsonwebtoken", "jspdf", "bcryptjs"]; _.entityExplorer.ExpandCollapseEntity("Libraries"); _.installer.OpenInstaller(); @@ -54,26 +74,27 @@ describe("excludeForAirgap", "Tests JS Libraries", () => { } }); - it("5. Checks installation in exported/forked app", () => { + it("6. Checks installation in exported/forked app", () => { _.homePage.NavigateToHome(); _.homePage.ImportApp("library_export.json"); - _.agHelper.AssertContains("true"); + _.homePage.AssertImportToast(); + _.agHelper.ValidateToastMessage("true"); _.agHelper.WaitUntilAllToastsDisappear(); //Checks installation in forked app _.homePage.NavigateToHome(); _.homePage.ForkApplication("Library_export"); - _.agHelper.AssertContains("true"); + _.agHelper.ValidateToastMessage("true"); _.agHelper.WaitUntilAllToastsDisappear(); //Deploy app and check installation _.deployMode.DeployApp(); _.agHelper.WaitUntilToastDisappear("true"); _.deployMode.NavigateBacktoEditor(); - _.agHelper.AssertContains("true"); + _.agHelper.ValidateToastMessage("true"); }); - it("6. Tests library access and installation in public apps", () => { + it("7. Tests library access and installation in public apps", () => { let appURL = ""; cy.get(HomePage.shareApp).click(); //@ts-expect-error no type access diff --git a/app/client/cypress/e2e/Regression/ClientSide/JSObject/Bug9585_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/JSObject/Bug9585_spec.ts index cbe69128a4..7f80cb8a4b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/JSObject/Bug9585_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/JSObject/Bug9585_spec.ts @@ -15,10 +15,8 @@ describe("List no functions on empty collection", () => { } }`, { - paste: true, completeReplace: true, toRun: false, - shouldCreateNewJSObj: true, prettify: false, }, ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/JSObject/JSObjectMutation_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/JSObject/JSObjectMutation_spec.ts index 3488d7a6e5..09d555941f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/JSObject/JSObjectMutation_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/JSObject/JSObjectMutation_spec.ts @@ -90,4 +90,52 @@ describe("JSObject testing", () => { expect($label).contains("[]"); }); }); + + it("6. Bug 27978 Check assignment should not get overridden by evaluation", () => { + _.entityExplorer.DragNDropWidget(_.draggableWidgets.TEXT, 400, 400); + _.propPane.TypeTextIntoField( + "Text", + `{{JSObject1.data.length ? 'id-' + JSObject1.data[0].id : 'Not Set' }}`, + true, + false, + ); + _.entityExplorer.NavigateToSwitcher("Explorer"); + _.apiPage.CreateAndFillApi( + _.dataManager.dsValues[_.dataManager.defaultEnviorment].mockApiUrl, + ); + const JS_OBJECT_BODY = `export default { + data: [], + async getData() { + await Api1.run() + return Api1.data + }, + async myFun1() { + this.data = await this.getData(); + console.log(this.data); + }, + async myFun2() { + const data = await this.getData(); + data.push({ name: "test123" }) + this.data = data; + console.log(this.data); + }, + }`; + _.jsEditor.CreateJSObject(JS_OBJECT_BODY, { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + }); + _.jsEditor.SelectFunctionDropdown("myFun1"); + _.jsEditor.RunJSObj(); + _.entityExplorer.SelectEntityByName("Text2", "Widgets"); + _.agHelper.AssertContains("id-1"); + _.agHelper.RefreshPage(); + _.agHelper.AssertContains("Not Set"); + _.entityExplorer.SelectEntityByName("JSObject1", "Queries/JS"); + _.jsEditor.SelectFunctionDropdown("myFun2"); + _.jsEditor.RunJSObj(); + _.entityExplorer.SelectEntityByName("Text2", "Widgets"); + _.agHelper.AssertContains("id-1"); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Linting/BasicLint_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Linting/BasicLint_spec.ts index ba7f85703b..ed608f9636 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Linting/BasicLint_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Linting/BasicLint_spec.ts @@ -345,7 +345,7 @@ describe("Linting", () => { entityExplorer.ExpandCollapseEntity("Libraries"); // install the library installer.OpenInstaller(); - installer.installLibrary("uuidjs", "UUID"); + installer.InstallLibrary("uuidjs", "UUID"); installer.CloseInstaller(); agHelper.AssertElementAbsence(locators._lintErrorElement); @@ -355,7 +355,7 @@ describe("Linting", () => { agHelper.AssertElementExist(locators._lintErrorElement); agHelper.Sleep(2000); installer.OpenInstaller(); - installer.installLibrary("uuidjs", "UUID"); + installer.InstallLibrary("uuidjs", "UUID"); installer.CloseInstaller(); homePage.NavigateToHome(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Linting/EntityPropertiesLint_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Linting/EntityPropertiesLint_spec.ts index bd61010eab..7686f7e24e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Linting/EntityPropertiesLint_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Linting/EntityPropertiesLint_spec.ts @@ -33,13 +33,10 @@ describe("Linting of entity properties", () => { cy.wait(200); cy.focused().blur(); propPane.UpdatePropertyFieldValue("Label", `{{Api1.${invalidProperty}}}`); - cy.get(locators._lintErrorElement) - .should("have.length", 2) - .first() - .trigger("mouseover"); - agHelper - .AssertContains(`"${invalidProperty}" doesn't exist in Api1`) - .should("exist"); + agHelper.AssertElementLength(locators._lintErrorElement, 2); + agHelper.HoverElement(locators._lintErrorElement); + agHelper.AssertContains(`"${invalidProperty}" doesn't exist in Api1`); + agHelper.GetNClick(locators._canvas); }); it("2. Shows correct lint error when wrong JSObject property is binded", () => { @@ -72,10 +69,8 @@ describe("Linting of entity properties", () => { `{{JSObject1.${invalidProperty}}}`, ); // Assert lint errors - cy.get(locators._lintErrorElement) - .should("have.length", 2) - .first() - .trigger("mouseover"); + agHelper.AssertElementLength(locators._lintErrorElement, 2); + agHelper.HoverElement(locators._lintErrorElement); agHelper.AssertContains(`"${invalidProperty}" doesn't exist in JSObject1`); // Edit JS Object and add "unknown" function @@ -96,10 +91,8 @@ describe("Linting of entity properties", () => { }); // select button, and assert that lint error is present entityExplorer.SelectEntityByName("Button1", "Widgets"); - cy.get(locators._lintErrorElement) - .should("have.length", 2) - .first() - .trigger("mouseover"); + agHelper.AssertElementLength(locators._lintErrorElement, 2); + agHelper.HoverElement(locators._lintErrorElement); agHelper.AssertContains(`'JSObject1' is not defined`); // create js object jsEditor.CreateJSObject( diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoFillWidgets_Reflow_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoFillWidgets_Reflow_spec.ts index a0dedac4c7..50d73c4073 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoFillWidgets_Reflow_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoFillWidgets_Reflow_spec.ts @@ -31,7 +31,7 @@ describe("Copy paste widget related tests for Auto layout", () => { "wrap", ); }); - it.skip("2. Auto Layout Reflow should work in public apps as well", () => { + it("2. Auto Layout Reflow should work in public apps as well", () => { let currentUrl = ""; cy.url().then((url) => { currentUrl = url; diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Container_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Container_spec.ts index 4a3b3a358e..84f9bcb276 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Container_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Container_spec.ts @@ -1,5 +1,5 @@ import { WIDGET_PADDING } from "../../../../../src/constants/WidgetConstants"; -import { MOBILE_ROW_GAP } from "../../../../../src/utils/autoLayout/constants"; +import { MOBILE_ROW_GAP } from "../../../../../src/layoutSystems/common/utils/constants"; import { agHelper, autoLayout, diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Form_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Form_spec.ts index b8db906df0..063c4a6755 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Form_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Form_spec.ts @@ -2,7 +2,7 @@ import { WIDGET_PADDING } from "../../../../../src/constants/WidgetConstants"; import { MOBILE_ROW_GAP, ROW_GAP, -} from "../../../../../src/utils/autoLayout/constants"; +} from "../../../../../src/layoutSystems/common/utils/constants"; import { agHelper, autoLayout, diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Modal_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Modal_spec.ts index ef7f36900e..94292c89e5 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Modal_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Modal_spec.ts @@ -2,7 +2,7 @@ import { WIDGET_PADDING } from "../../../../../src/constants/WidgetConstants"; import { MOBILE_ROW_GAP, ROW_GAP, -} from "../../../../../src/utils/autoLayout/constants"; +} from "../../../../../src/layoutSystems/common/utils/constants"; import { agHelper, autoLayout, diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Tabs_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Tabs_spec.ts index 9df1eda345..7145a5ccd1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Tabs_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/AutoHeight_Tabs_spec.ts @@ -2,7 +2,7 @@ import { WIDGET_PADDING } from "../../../../../src/constants/WidgetConstants"; import { MOBILE_ROW_GAP, ROW_GAP, -} from "../../../../../src/utils/autoLayout/constants"; +} from "../../../../../src/layoutSystems/common/utils/constants"; import { agHelper, autoLayout, diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/ConversionAlgorithm_FixedLayout_Mobile_Validation_Spec.js b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/ConversionAlgorithm_FixedLayout_Mobile_Validation_Spec.js index a0ebb981c1..e1fc44e483 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/ConversionAlgorithm_FixedLayout_Mobile_Validation_Spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/ConversionAlgorithm_FixedLayout_Mobile_Validation_Spec.js @@ -65,5 +65,6 @@ describe("Auto conversion algorithm usecases for fixed Layout", function () { }); }); }); + agHelper.Sleep(); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Row_Gap_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Row_Gap_spec.ts index a2158c0828..d7902cee78 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Row_Gap_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Row_Gap_spec.ts @@ -1,8 +1,8 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; import { - ROW_GAP, MOBILE_ROW_GAP, -} from "../../../../../src/utils/autoLayout/constants"; + ROW_GAP, +} from "../../../../../src/layoutSystems/common/utils/constants"; describe("Validating use cases for Auto Dimension", () => { before(() => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Snipping_mode_Basic_test.js b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Snipping_mode_Basic_test.js index 555b89e200..38f34eaced 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Snipping_mode_Basic_test.js +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/Snipping_mode_Basic_test.js @@ -1,15 +1,13 @@ -const queryLocators = require("../../../../locators/QueryEditor.json"); -const queryEditor = require("../../../../locators/QueryEditor.json"); import * as _ from "../../../../support/Objects/ObjectsCore"; +import { Widgets } from "../../../../support/Pages/DataSources"; let datasourceName; describe("Add widget - Postgress DataSource", function () { beforeEach(() => { - cy.startRoutesForDatasource(); - cy.createPostgresDatasource(); - cy.get("@saveDatasource").then((httpResponse) => { - datasourceName = httpResponse.response.body.data.name; + _.dataSources.CreateDataSource("Postgres"); + cy.get("@dsName").then(($dsName) => { + datasourceName = $dsName; }); }); @@ -22,9 +20,7 @@ describe("Add widget - Postgress DataSource", function () { _.dataSources.EnterQuery("select * from public.configs"); cy.WaitAutoSave(); cy.runQuery(); - cy.get(queryEditor.suggestedTableWidget).click(); - cy.CheckAndUnfoldEntityItem("Widgets"); - cy.selectEntityByName("Table1"); + _.dataSources.AddSuggestedWidget(Widgets.Table); cy.isSelectRow(1); cy.readTableV2dataPublish("1", "0").then((tabData) => { cy.log("the value is " + tabData); diff --git a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/SuggestedWidgets_spec.js b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/SuggestedWidgets_spec.js index af63de96bc..f77498bf60 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/SuggestedWidgets_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/MobileResponsiveTests/SuggestedWidgets_spec.js @@ -5,17 +5,10 @@ import { agHelper, } from "../../../../support/Objects/ObjectsCore"; import { Widgets } from "../../../../support/Pages/DataSources"; -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; describe("Check Suggested Widgets Feature in auto-layout", function () { before(() => { autoLayout.ConvertToAutoLayoutAndVerify(false); - featureFlagIntercept( - { - ab_ds_binding_enabled: false, - }, - false, - ); agHelper.RefreshPage(); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Onboarding/FirstTimeUserOnboarding_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Onboarding/FirstTimeUserOnboarding_spec.js index bdfd8f4790..8e290495ac 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Onboarding/FirstTimeUserOnboarding_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Onboarding/FirstTimeUserOnboarding_spec.js @@ -7,6 +7,7 @@ import { onboarding, draggableWidgets, debuggerHelper, + dataSources, } from "../../../../support/Objects/ObjectsCore"; const datasource = require("../../../../locators/DatasourcesEditor.json"); @@ -118,7 +119,7 @@ describe("FirstTimeUserOnboarding", function () { cy.get(OnboardingLocator.checklistDatasourceBtn).click(); cy.get(OnboardingLocator.datasourcePage).should("be.visible"); cy.get(datasource.MongoDB).click(); - cy.fillMongoDatasourceForm(); + dataSources.FillMongoDSForm(); cy.generateUUID().then((uid) => { datasourceName = `Mongo CRUD ds ${uid}`; cy.renameDatasource(datasourceName); @@ -216,7 +217,7 @@ describe("FirstTimeUserOnboarding", function () { false, ); agHelper.Sleep(500); - agHelper.GetNClick(debuggerHelper.locators._helpButton); + agHelper.GetNClick(debuggerHelper.locators._helpButton, 0, true); agHelper.AssertElementVisibility(OnboardingLocator.checklistDatasourceBtn); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/ConnectToWidget_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/ConnectToWidget_spec.ts new file mode 100644 index 0000000000..b3b88ec94e --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/ConnectToWidget_spec.ts @@ -0,0 +1,109 @@ +import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator"; +import { OneClickBinding } from "../spec_utility"; +import { + agHelper, + assertHelper, + dataSources, + draggableWidgets, + entityExplorer, + locators, + table, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +const oneClickBinding = new OneClickBinding(); + +describe("JSONForm widget one click binding feature", () => { + let datasourceName: string; + + it("1.Connect to a table widget", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 200, 200); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 600, 400); + + entityExplorer.NavigateToSwitcher("Explorer"); + + dataSources.CreateDataSource("Postgres"); + + cy.get("@dsName").then((dsName) => { + datasourceName = dsName as unknown as string; + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("Table1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${datasourceName}`, + datasourceName, + "public.employees", + { + searchableColumn: "first_name", + }, + ); + }); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + assertHelper.AssertNetworkStatus("@postExecute"); + + agHelper.Sleep(2000); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("JSONForm1", "Widgets"); + + agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector); + agHelper.GetNClick( + oneClickBindingLocator.datasourceQuerySelector("Table1"), + ); + + agHelper.Sleep(2000); + + table.SelectTableRow(0, 1, true, "v2"); + + table.ReadTableRowColumnData(0, 1, "v2").then((cellData) => { + agHelper + .GetText(locators._jsonFormInputField("last_name"), "val") + .should("be.equal", cellData); + }); + + agHelper.GetNClick(locators._jsonFormSubmitBtn, 0, true); + + agHelper.AssertElementVisibility(locators._toastMsg); + agHelper.AssertElementVisibility( + locators._specificToast("onSubmit event is not configured for JSONForm1"), + ); + }); + + it("Connect to a list widget", () => { + entityExplorer.AddNewPage("New blank page"); + + entityExplorer.DragDropWidgetNVerify(draggableWidgets.LIST_V2, 200, 200); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 600, 400); + + agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector); + agHelper.GetNClick(oneClickBindingLocator.datasourceQuerySelector("List1")); + + agHelper.Sleep(2000); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("List1", "Widgets"); + + propPane.UpdatePropertyFieldValue("Default selected item", "001"); + + agHelper + .GetText(locators._jsonFormInputField("name"), "val") + .then((text) => { + agHelper.Sleep(500); + agHelper.GetText(".t--widget-textwidget span", "text").then((val) => { + expect(val).to.eq(text); + }); + }); + + agHelper.GetNClick(locators._jsonFormSubmitBtn, 0, true); + + agHelper.AssertElementVisibility(locators._toastMsg); + agHelper.AssertElementVisibility( + locators._specificToast("onSubmit event is not configured for JSONForm1"), + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/FieldConfigModal_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/FieldConfigModal_spec.ts new file mode 100644 index 0000000000..f6a5c8a06b --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/FieldConfigModal_spec.ts @@ -0,0 +1,73 @@ +import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator"; +import { OneClickBinding } from "../spec_utility"; +import { + agHelper, + entityExplorer, + dataSources, + draggableWidgets, + locators, +} from "../../../../../support/Objects/ObjectsCore"; + +const oneClickBinding = new OneClickBinding(); + +describe("JSONForm widget one click binding feature", () => { + it("1.tests select/unselect fields for json form widget", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 450, 200); + + entityExplorer.NavigateToSwitcher("Explorer"); + + dataSources.CreateDataSource("Postgres"); + + cy.get("@dsName").then((dsName) => { + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("JSONForm1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${dsName}`, + dsName, + "public.employees", + ); + }); + + // Open the column selector modal + agHelper.GetNClick(oneClickBindingLocator.columnSelectorModalTrigger); + + // Assert that the primary column is unchecked + agHelper.AssertAttribute( + oneClickBindingLocator.checkBox, + "data-checked", + "false", + ); + + // Deselect some columns + const deselectColumns = ["title_of_courtesy", "birth_date", "hire_date"]; + + deselectColumns.forEach((column) => { + agHelper.GetNClick( + oneClickBindingLocator.columnSelectorField(column), + 0, + true, + ); + }); + + // Save the column selection + agHelper.GetNClick(oneClickBindingLocator.columnselectorModalSaveBtn); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + agHelper.Sleep(2000); + + const selectedColumns = ["last_name", "first_name", "title"]; + + // Assert that the selected columns are present in the form + selectedColumns.forEach((column) => { + agHelper.AssertElementExist(locators._draggableFieldConfig(column)); + }); + + // Assert that the deselected columns are not present in the form + deselectColumns.forEach((column) => { + agHelper.AssertElementAbsence(locators._draggableFieldConfig(column)); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/mongoDb_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/mongoDb_spec.ts new file mode 100644 index 0000000000..ac14e77f04 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/mongoDb_spec.ts @@ -0,0 +1,141 @@ +import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator"; +import { OneClickBinding } from "../spec_utility"; +import { + agHelper, + assertHelper, + dataSources, + draggableWidgets, + entityExplorer, + locators, + table, +} from "../../../../../support/Objects/ObjectsCore"; + +const oneClickBinding = new OneClickBinding(); + +describe("JSONForm widget one click binding feature", () => { + let datasourceName: string; + it("1.Create flow: should check that queries are created and bound to jsonform widget properly", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 450, 200); + + entityExplorer.NavigateToSwitcher("Explorer"); + + dataSources.CreateDataSource("Mongo"); + + cy.get("@dsName").then((dsName) => { + datasourceName = dsName as unknown as string; + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("JSONForm1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${datasourceName}`, + datasourceName, + "netflix", + { + formType: "Create records", + }, + ); + }); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + agHelper.Sleep(2000); + + const columns = [ + "contentRating", + "contentType", + "creator", + "description", + "director", + "genre", + "name", + "numberOfSeasons", + "releasedDate", + "seasonStartDate", + "url", + ]; + + columns.forEach((column) => { + agHelper.AssertElementExist(locators._draggableFieldConfig(column)); + }); + }); + + it("2.Update flow: should check that queries are created and bound to table jsonform widget properly ", () => { + entityExplorer.AddNewPage("New blank page"); + + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 200, 200); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 600, 400); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("Table1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${datasourceName}`, + datasourceName, + "netflix", + { + searchableColumn: "creator", + }, + ); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + assertHelper.AssertNetworkStatus("@postExecute"); + + agHelper.Sleep(2000); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("JSONForm1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${datasourceName}`, + datasourceName, + "netflix", + { + formType: "Edit records", + defaultValues: "Table1", + dataIdentifier: "id", + }, + ); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + assertHelper.AssertNetworkStatus("@postExecute"); + + agHelper.Sleep(2000); + + table.SelectTableRow(0, 3, true, "v2"); + + table.ReadTableRowColumnData(0, 3, "v2").then((cellData) => { + agHelper + .GetText(locators._jsonFormInputField("creator"), "val") + .should("be.equal", cellData); + }); + + agHelper + .GetElement(locators._jsonFormInputField("creator")) + .clear() + .type("Doe"); + agHelper + .GetText(locators._jsonFormInputField("creator"), "val") + .should("be.equal", "Doe"); + + agHelper.GetNClick(locators._jsonFormSubmitBtn, 0, true); + + agHelper.Sleep(2000); + + // reloading because we don't create select query with json form, so we need to reload the page to get the updated data + cy.reload(); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("Table1", "Widgets"); + + table.ReadTableRowColumnData(0, 3, "v2").then((cellData) => { + expect(cellData).to.eq("Doe"); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/postgres_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/postgres_spec.ts new file mode 100644 index 0000000000..e87a608d5f --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/postgres_spec.ts @@ -0,0 +1,135 @@ +import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator"; +import { OneClickBinding } from "../spec_utility"; +import { + agHelper, + assertHelper, + dataSources, + draggableWidgets, + entityExplorer, + locators, + table, +} from "../../../../../support/Objects/ObjectsCore"; + +const oneClickBinding = new OneClickBinding(); + +describe("JSONForm widget one click binding feature", () => { + let datasourceName: string; + it("1.Create flow: should check that queries are created and bound to table jsonform widget properly ", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 450, 200); + + entityExplorer.NavigateToSwitcher("Explorer"); + + dataSources.CreateDataSource("Postgres"); + + cy.get("@dsName").then((dsName) => { + datasourceName = dsName as unknown as string; + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("JSONForm1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${datasourceName}`, + datasourceName, + "public.employees", + { + formType: "Create records", + }, + ); + }); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + agHelper.Sleep(2000); + + const columns = [ + "last_name", + "first_name", + "title", + "title_of_courtesy", + "birth_date", + "hire_date", + ]; + + columns.forEach((column) => { + agHelper.AssertElementExist(locators._draggableFieldConfig(column)); + }); + }); + + it("2.Update flow: should check that queries are created and bound to table jsonform widget properly ", () => { + entityExplorer.AddNewPage("New blank page"); + + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 200, 200); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 600, 400); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("Table1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${datasourceName}`, + datasourceName, + "public.employees", + { + searchableColumn: "first_name", + }, + ); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + assertHelper.AssertNetworkStatus("@postExecute"); + + agHelper.Sleep(2000); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("JSONForm1", "Widgets"); + + oneClickBinding.ChooseAndAssertForm( + `${datasourceName}`, + datasourceName, + "public.employees", + { + formType: "Edit records", + defaultValues: "Table1", + dataIdentifier: "id", + }, + ); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + + assertHelper.AssertNetworkStatus("@postExecute"); + + agHelper.Sleep(2000); + + table.SelectTableRow(0, 1, true, "v2"); + + table.ReadTableRowColumnData(0, 1, "v2").then((cellData) => { + agHelper + .GetText(locators._jsonFormInputField("last_name"), "val") + .should("be.equal", cellData); + }); + + agHelper + .GetElement(locators._jsonFormInputField("last_name")) + .clear() + .type("Doe"); + agHelper + .GetText(locators._jsonFormInputField("last_name"), "val") + .should("be.equal", "Doe"); + + agHelper.GetNClick(locators._jsonFormSubmitBtn, 0, true); + + agHelper.Sleep(2000); + + // reloading because we don't create select query with json form, so we need to reload the page to get the updated data + cy.reload(); + + entityExplorer.NavigateToSwitcher("Widgets"); + + entityExplorer.SelectEntityByName("Table1", "Widgets"); + + table.ReadTableRowColumnData(0, 1, "v2").then((cellData) => { + expect(cellData).to.eq("Doe"); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/PropertyControl_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/PropertyControl_spec.ts index a7e89aa674..76cbfdc0c7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/PropertyControl_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/PropertyControl_spec.ts @@ -116,7 +116,7 @@ describe("excludeForAirgap", "One click binding control", () => { dataSources.CreatePlugIn("Mongo"); agHelper.RenameWithInPane("myinvalidds", false); - agHelper.UpdateInputValue(dataSources._host, "127.0.0.1"); + agHelper.UpdateInputValue(dataSources._host(), "127.0.0.1"); agHelper.UpdateInputValue(dataSources._port, "8000"); dataSources.SaveDatasource(); @@ -144,7 +144,7 @@ describe("excludeForAirgap", "One click binding control", () => { dataSources.CreatePlugIn("Mongo"); agHelper.RenameWithInPane(`dummy${I}`, false); - agHelper.UpdateInputValue(dataSources._host, "127.0.0.1"); + agHelper.UpdateInputValue(dataSources._host(), "127.0.0.1"); agHelper.UpdateInputValue(dataSources._port, "8000"); dataSources.SaveDatasource(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts index 60d4106c7b..910cd820bf 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts @@ -1,4 +1,7 @@ -import { agHelper } from "../../../../support/Objects/ObjectsCore"; +import { + agHelper, + assertHelper, +} from "../../../../support/Objects/ObjectsCore"; import oneClickBindingLocator from "../../../../locators/OneClickBindingLocator"; export class OneClickBinding { @@ -16,11 +19,7 @@ export class OneClickBinding { agHelper.GetNClick(oneClickBindingLocator.datasourceSelector(source)); - cy.wait("@getDatasourceStructure").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); + assertHelper.AssertNetworkStatus("@getDatasourceStructure"); agHelper.AssertElementExist(oneClickBindingLocator.connectData); @@ -66,7 +65,7 @@ export function expandLoadMoreOptions() { if ($ele.find(oneClickBindingLocator.loadMore).length > 0) { const length = $ele.find(oneClickBindingLocator.loadMore).length; new Array(length).fill(" ").forEach((d, i) => { - agHelper.GetNClick(oneClickBindingLocator.loadMore, i); + agHelper.GetNClick(oneClickBindingLocator.loadMore, 0); }); } }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Analytics_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Analytics_spec.js index 6c391bb962..e5ce057584 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Analytics_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Analytics_spec.js @@ -1,4 +1,3 @@ -let appId; import { agHelper, homePage } from "../../../../support/Objects/ObjectsCore"; describe( @@ -40,11 +39,7 @@ describe( req.continue(); }); cy.get(".t--new-button").should("be.visible"); - cy.generateUUID().then((id) => { - appId = id; - cy.CreateAppInFirstListedWorkspace(id); - localStorage.setItem("AppName", appId); - }); + homePage.CreateNewApplication(); cy.wait(3000); cy.window().then(() => { cy.wrap(interceptFlag).should("eq", false); @@ -63,11 +58,8 @@ describe( interceptFlag = true; req.continue(); }); - cy.generateUUID().then((id) => { - appId = id; - cy.CreateAppInFirstListedWorkspace(id); - localStorage.setItem("AppName", appId); - }); + + homePage.CreateNewApplication(); cy.wait(3000); cy.window().then(() => { cy.wrap(interceptFlag).should("eq", false); @@ -86,11 +78,7 @@ describe( interceptFlag = true; req.continue(); }); - cy.generateUUID().then((id) => { - appId = id; - cy.CreateAppInFirstListedWorkspace(id); - localStorage.setItem("AppName", appId); - }); + homePage.CreateNewApplication(); cy.wait(3000); cy.window().then(() => { cy.wrap(interceptFlag).should("eq", false); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ApplicationURL_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ApplicationURL_spec.js index 854e940e11..d3e1b982e3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ApplicationURL_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ApplicationURL_spec.js @@ -9,6 +9,7 @@ import { describe("Slug URLs", () => { let applicationName; let applicationId; + it("1. Checks URL redirection from legacy URLs to slug URLs", () => { applicationId = localStorage.getItem("applicationId"); cy.location("pathname").then((pathname) => { @@ -18,7 +19,10 @@ describe("Slug URLs", () => { cy.wait(10000); cy.location("pathname").then((pathname) => { const pageId = pathname.split("/")[3]?.split("-").pop(); - const appName = localStorage.getItem("AppName"); + const appName = localStorage + .getItem("appName") + .replace(/\s+/g, "-") + .toLowerCase(); expect(pathname).to.be.equal( `/app/${appName}/page1-${pageId}/edit`, ); @@ -28,7 +32,7 @@ describe("Slug URLs", () => { }); }); - it("2. Checks if application slug updates on the URL when application name changes", () => { + it("2. Checks if application slug updates & page slug updates on the URL when application name/page name changes", () => { cy.generateUUID().then((appName) => { applicationName = appName; homePage.RenameApplication(applicationName); @@ -38,29 +42,27 @@ describe("Slug URLs", () => { expect(pathname).to.be.equal(`/app/${appName}/page1-${pageId}/edit`); }); }); - }); - - it("3. Checks if page slug updates on the URL when page name changes", () => { entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Page1", action: "Edit name", }); - cy.get(explorer.editEntity).last().type("Page renamed", { force: true }); - cy.get("body").click(0, 0, { force: true }); - cy.wait("@updatePage").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); - cy.location("pathname").then((pathname) => { + cy.get(explorer.editEntity) + .last() + .type("Renamed" + "{enter}", { force: true }); + agHelper.Sleep(2000); //for new name to settle & url to update + assertHelper.AssertNetworkStatus("updatePage"); + // cy.location("pathname").then((pathname) => { + cy.url().then((url) => { + const urlObject = new URL(url); + const pathname = urlObject.pathname; const pageId = pathname.split("/")[3]?.split("-").pop(); expect(pathname).to.be.equal( - `/app/${applicationName}/page-renamed-${pageId}/edit`, + `/app/${applicationName}/renamed-${pageId}/edit`, ); }); }); - it("4. Check the url of old applications, upgrades version and compares appsmith.URL values", () => { + it("3. Check the url of old applications, upgrades version and compares appsmith.URL values", () => { cy.request("PUT", `/api/v1/applications/${applicationId}`, { applicationVersion: 1, }).then((response) => { @@ -137,9 +139,9 @@ describe("Slug URLs", () => { }); }); - it("5. Checks redirect url", () => { + it("4. Checks redirect url", () => { cy.url().then((url) => { - cy.LogOut(); + cy.LogOut(false); agHelper.VisitNAssert(url + "?embed=true&a=b", "signUpLogin"); agHelper.Sleep(2000); // cy.location().should((loc) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ExportApplication_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ExportApplication_spec.js index da5312774a..c564f2b135 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ExportApplication_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ExportApplication_spec.js @@ -1,49 +1,21 @@ import { REPO, CURRENT_REPO } from "../../../../fixtures/REPO"; import homePageLocators from "../../../../locators/HomePage"; import { agHelper, homePage } from "../../../../support/Objects/ObjectsCore"; -const commonlocators = require("../../../../locators/commonlocators.json"); +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; describe("Export application as a JSON file", function () { - let workspaceId; - let appid; - let appname; + let workspaceId, appid; before(() => { agHelper.AddDsl("displayWidgetDsl"); }); - it("1. Check if exporting app flow works as expected", function () { - cy.get(commonlocators.homeIcon).click({ force: true }); - appname = localStorage.getItem("AppName"); - cy.get(homePageLocators.searchInput).type(appname); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(2000); - - // cy.get(homePageLocators.applicationCard).first().trigger("mouseover"); - cy.get(homePageLocators.appMoreIcon).first().click({ force: true }); - cy.get(homePageLocators.exportAppFromMenu).click({ force: true }); - agHelper.ValidateToastMessage("Successfully exported"); - // fetching the exported app file manually to be verified. - cy.get(`a[id=t--export-app-link]`).then((anchor) => { - const url = anchor.prop("href"); - cy.request(url).then(({ headers }) => { - expect(headers).to.have.property("content-type", "application/json"); - expect(headers) - .to.have.property("content-disposition") - .that.includes("attachment;") - .and.includes(`filename*=UTF-8''${appname}.json`); - }); - }); - cy.LogOut(); - }); - - it("2. User with admin access,should be able to export the app", function () { + it("1. User with admin access,should be able to export the app", function () { + //cy.LogOut(); if (CURRENT_REPO === REPO.CE) { - cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); - homePage.NavigateToHome(); agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { - homePage.CreateNewWorkspace("exportApp" + uid); + homePage.CreateNewWorkspace("exportApp" + uid, true); homePage.CreateAppInWorkspace("exportApp" + uid, "App" + uid); appid = "App" + uid; //cy.get("h2").contains("Drag and drop a widget here"); @@ -78,8 +50,11 @@ describe("Export application as a JSON file", function () { } }); - it("3. User with developer access,should not be able to export the app", function () { + it("2. User with developer access,should not be able to export the app", function () { cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + featureFlagIntercept({ license_gac_enabled: true }); + agHelper.Sleep(2000); + homePage.NavigateToHome(); agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { @@ -113,8 +88,11 @@ describe("Export application as a JSON file", function () { cy.LogOut(); }); - it("4. User with viewer access,should not be able to export the app", function () { + it("3. User with viewer access,should not be able to export the app", function () { homePage.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + featureFlagIntercept({ license_gac_enabled: true }); + agHelper.Sleep(2000); + homePage.NavigateToHome(); agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js index aa5108bb33..f45f3d2708 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js @@ -1,4 +1,5 @@ import commonlocators from "../../../../locators/commonlocators.json"; +import { homePage } from "../../../../support/Objects/ObjectsCore"; import { ObjectsRegistry } from "../../../../support/Objects/Registry"; const { @@ -34,10 +35,8 @@ describe("Debugger logs", function () { cy.get(".t--property-control-visible").find(".t--js-toggle").click(); cy.testJsontext("visible", "Test"); cy.get(commonlocators.homeIcon).click({ force: true }); - cy.generateUUID().then((id) => { - cy.CreateAppInFirstListedWorkspace(id); - debuggerHelper.AssertErrorCount(0); - }); + homePage.CreateNewApplication(); + debuggerHelper.AssertErrorCount(0); }); it("3. Console log on button click with normal moustache binding", function () { diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Omnibar_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Omnibar_spec.js index 528a735422..9775cc4851 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Omnibar_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Omnibar_spec.js @@ -1,5 +1,4 @@ const omnibar = require("../../../../locators/Omnibar.json"); -const commonlocators = require("../../../../locators/commonlocators.json"); import { agHelper, entityExplorer, @@ -18,10 +17,11 @@ describe("Omnibar functionality test cases", () => { it("1. Bug #15104 Docs tab opens after clicking on learn more link from property pane", function () { cy.dragAndDropToCanvas(draggableWidgets.AUDIO, { x: 300, y: 500 }); + agHelper.Sleep(2000); deployMode.StubWindowNAssert( '//span[text()="Learn more"]', - "connect-datasource", - "getWorkspace", + "connect-to-a-database", + "getPluginForm", ); }); @@ -115,7 +115,7 @@ describe("Omnibar functionality test cases", () => { deployMode.StubWindowNAssert( omnibar.discordLink, "https://discord.com/invite/rBTTVJp", - "getWorkspace", + "getPluginForm", ); }, ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts index f7fd6faffa..d5033b1f39 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts @@ -1,22 +1,30 @@ const explorer = require("../../../../locators/explorerlocators.json"); const testdata = require("../../../../fixtures/testdata.json"); -import * as _ from "../../../../support/Objects/ObjectsCore"; + +import { + agHelper, + entityExplorer, + propPane, + apiPage, + debuggerHelper, +} from "../../../../support/Objects/ObjectsCore"; describe("Check debugger logs state when there are onPageLoad actions", function () { before(() => { - _.agHelper.AddDsl("debuggerTableDsl"); + agHelper.AddDsl("debuggerTableDsl"); }); + it("1. Check debugger logs state when there are onPageLoad actions", function () { - _.entityExplorer.SelectEntityByName("Table1", "Widgets"); - _.propPane.UpdatePropertyFieldValue("Table data", "{{TestApi.data.users}}"); - _.apiPage.CreateAndFillApi(testdata.baseUrl + testdata.methods, "TestApi"); - _.apiPage.RunAPI(); - _.agHelper.GetNClick(explorer.addWidget); - _.agHelper.RefreshPage(); + entityExplorer.SelectEntityByName("Table1", "Widgets"); + propPane.UpdatePropertyFieldValue("Table data", "{{TestApi.data.users}}"); + apiPage.CreateAndFillApi(testdata.baseUrl + testdata.methods, "TestApi"); + apiPage.RunAPI(); + agHelper.GetNClick(explorer.addWidget); + agHelper.RefreshPage(); // Wait for the debugger icon to be visible - _.agHelper.AssertElementVisibility(".t--debugger-count"); + agHelper.AssertElementVisibility(".t--debugger-count"); // debuggerHelper.isErrorCount(0); cy.wait("@postExecute"); - _.debuggerHelper.AssertErrorCount(1); + debuggerHelper.AssertErrorCount(1); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js index 79d6034eba..33f286819d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js @@ -3,9 +3,6 @@ const testdata = require("../../../../fixtures/testdata.json"); const datasource = require("../../../../locators/DatasourcesEditor.json"); const datasourceEditor = require("../../../../locators/DatasourcesEditor.json"); const datasourceFormData = require("../../../../fixtures/datasources.json"); -const queryLocators = require("../../../../locators/QueryEditor.json"); -import * as _ from "../../../../support/Objects/ObjectsCore"; - import { agHelper, jsEditor, @@ -47,7 +44,7 @@ describe("Undo/Redo functionality", function () { }); cy.get(datasourceEditor.password).should("be.empty").wait(1000); cy.get(datasourceEditor.saveBtn).click({ force: true }); - dataSources.AssertDSActive(postgresDatasourceName); + dataSources.AssertDSInActiveList(postgresDatasourceName); }); }); @@ -60,8 +57,7 @@ describe("Undo/Redo functionality", function () { "https://mock-api.appsmith.com/users", //testing placeholder! ); cy.enterDatasourceAndPath(testdata.baseUrl, testdata.methods); - agHelper.RemoveTooltip("Add a new query/JS Object"); - + agHelper.RemoveUIElement("Tooltip", "Add a new query/JS Object"); cy.get(`${apiwidget.headerKey}`).type("Authorization"); cy.get("body").click(0, 0); cy.get(apiwidget.settings).click({ force: true }); @@ -101,20 +97,8 @@ describe("Undo/Redo functionality", function () { parseSpecialCharSequences: false, }); cy.get("body").click(0, 0); - // verifying Relationships is visible on dynamic binding - cy.get(".icon-text") - .eq(1) - .within(() => { - cy.get(".connection-type").should("have.text", "Incoming entities"); - }); - cy.get(".connection span").should("have.text", "FirstAPI"); - - cy.get(".icon-text") - .last() - .within(() => { - cy.get(".connection-type").should("have.text", "Outgoing entities"); - }); + // Removed the verification of relationships as we have removed the `Relationships` element from the new bindings UI cy.get("body").type(`{${modifierKey}}z`); cy.get(".CodeEditorTarget textarea").should( @@ -159,25 +143,22 @@ describe("Undo/Redo functionality", function () { // cy.get(".function-name").should("not.contain.text", "test"); }); - //Skipping this since its failing in CI - it.skip("5. Checks undo/redo for Authenticated APIs", () => { + it("5. Checks undo/redo for Authenticated APIs", () => { cy.NavigateToAPI_Panel(); cy.get(apiwidget.createAuthApiDatasource).click({ force: true }); cy.wait(2000); - cy.get("input[name='url']").type(testdata.baseUrl); - cy.get("input[name='headers[0].key']").type(testdata.headerKey); + agHelper.TypeText(dataSources._headerKey, testdata.headerKey); + agHelper.TypeText(dataSources._urlInputControl, testdata.baseUrl); + agHelper.Sleep(1000); cy.get("body").click(0, 0); cy.get("body").type(`{${modifierKey}}z`); - cy.get("body").type(`{${modifierKey}}z`); - cy.wait(2000); cy.get("input[name='url']").should("have.value", ""); + cy.get("body").type(`{${modifierKey}}z`); cy.get("input[name='headers[0].key']").should("have.value", ""); + cy.get("body").click(0, 0); cy.get("body").type(`{${modifierKey}}{shift}z`); cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get("input[name='url']").should( - "have.value", - "https://mock-api.appsmith.com/", - ); + cy.get("input[name='url']").should("have.value", testdata.baseUrl); cy.get("input[name='headers[0].key']").should("have.value", "Content-Type"); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js index 7ab77047c7..a1fc87d2e9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js @@ -2,18 +2,19 @@ import homePage from "../../../../locators/HomePage"; const commonlocators = require("../../../../locators/commonlocators.json"); describe("Update Application", () => { - let appname; + let appname, workspaceName; let iconname; - let colorname; let veryLongAppName = `gnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionih1gnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionih1${Math.random() .toString(36) .slice(2, -1)}`; it("1. Open the application menu and update name and then check whether update is reflected in the application card", () => { cy.get(commonlocators.homeIcon).click({ force: true }); - appname = localStorage.getItem("AppName"); + workspaceName = localStorage.getItem("workspaceName"); + appname = localStorage.getItem("appName"); + cy.get(homePage.searchInput).clear(); - cy.get(homePage.searchInput).type(appname); + cy.get(homePage.searchInput).type(workspaceName); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(2000); cy.get(homePage.appMoreIcon).first().click({ force: true }); @@ -43,7 +44,7 @@ describe("Update Application", () => { it("3. Check for errors in updating application name", () => { cy.get(commonlocators.homeIcon).click({ force: true }); cy.get(homePage.searchInput).clear(); - cy.get(homePage.searchInput).type(appname); + cy.get(homePage.searchInput).type(workspaceName); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(2000); cy.get(homePage.applicationCard).first().trigger("mouseover"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ProductRamps/PrivateEmbedRamp_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ProductRamps/PrivateEmbedRamp_spec.ts index 44d0e77302..bea139297e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ProductRamps/PrivateEmbedRamp_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ProductRamps/PrivateEmbedRamp_spec.ts @@ -1,34 +1,51 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; import { CURRENT_REPO, REPO } from "../../../../fixtures/REPO"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; describe("Private embed in-app ramp", () => { - function checkRampLink(section: string) { - const escapedSection = section.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); - const regexPattern = new RegExp( - `https:\\/\\/www\\.appsmith\\.com\\/pricing\\?source=CE&instance=.+&feature=private_embeds§ion=${escapedSection}`, + function checkRampTextInAppSettings() { + _.agHelper.AssertElementExist(_.inviteModal.locators._upgradeContent); + _.agHelper.AssertElementAbsence( + _.inviteModal.locators._shareSettingsButton, ); - + _.agHelper.GetNAssertElementText( + _.inviteModal.locators._privateEmbedRampAppSettings, + "To embed private Appsmith apps and seamlessly authenticate users through SSO", + "contain.text", + ); + checkRampLink(); + } + function checkRampTextInShareModal() { + _.inviteModal.SelectEmbedTab(); + _.agHelper.GetNAssertElementText( + _.inviteModal.locators._privateEmbedRampAppSettings, + "Embed private Appsmith apps and seamlessly authenticate users through SSO in our Business Edition", + "contain.text", + ); + checkRampLink(); + } + function checkRampLink() { cy.get(_.inviteModal.locators._privateEmbedRampLink) .should("have.attr", "href") .then((href) => { - expect(href).to.match(regexPattern); + expect(href).to.include("customer.appsmith.com"); }); } function checkAppSettingsRamp() { _.embedSettings.OpenEmbedSettings(); if (CURRENT_REPO === REPO.CE) { - _.agHelper.AssertElementExist(_.inviteModal.locators._upgradeContent); - _.agHelper.AssertElementAbsence( - _.inviteModal.locators._shareSettingsButton, - ); - _.agHelper.GetNAssertElementText( - _.inviteModal.locators._privateEmbedRampAppSettings, - "To embed private Appsmith apps and seamlessly authenticate users through SSO", - "contain.text", - ); - checkRampLink("app_settings"); + checkRampTextInAppSettings(); } else if (CURRENT_REPO === REPO.EE) { + featureFlagIntercept({ + license_private_embeds_enabled: false, + }); + _.embedSettings.OpenEmbedSettings(); + checkRampTextInAppSettings(); + featureFlagIntercept({ + license_private_embeds_enabled: true, + }); + _.embedSettings.OpenEmbedSettings(); _.agHelper.AssertElementAbsence(_.inviteModal.locators._upgradeContent); _.agHelper.AssertElementAbsence( _.inviteModal.locators._privateEmbedRampAppSettings, @@ -40,25 +57,33 @@ describe("Private embed in-app ramp", () => { function checkShareModalRamp() { _.inviteModal.OpenShareModal(); if (CURRENT_REPO === REPO.CE) { - _.inviteModal.SelectEmbedTab(); - _.agHelper.GetNAssertElementText( - _.inviteModal.locators._privateEmbedRampAppSettings, - "Embed private Appsmith apps and seamlessly authenticate users through SSO in our Business Edition", - "contain.text", - ); - checkRampLink("share_modal"); + checkRampTextInShareModal(); } else if (CURRENT_REPO === REPO.EE) { + featureFlagIntercept({ + license_private_embeds_enabled: false, + }); + _.inviteModal.OpenShareModal(); + checkRampTextInShareModal(); + featureFlagIntercept({ + license_private_embeds_enabled: true, + }); + _.inviteModal.OpenShareModal(); _.agHelper.AssertElementAbsence( _.inviteModal.locators._privateEmbedRampAppSettings, ); } } it("1. Ramp should be visibile to ADMIN and DEVELOPER", () => { + featureFlagIntercept({ license_gac_enabled: true }); + cy.wait(2000); + checkAppSettingsRamp(); checkShareModalRamp(); _.agHelper.GetNClick(_.homePage._homeIcon, 0, true, 2000); _.agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { + featureFlagIntercept({ license_gac_enabled: true }); + cy.wait(2000); let workspaceName: any = uid; _.homePage.CreateNewWorkspace(workspaceName); _.homePage.InviteUserToWorkspace( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Refactoring/Refactoring_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Refactoring/Refactoring_spec.ts index 211c2c8841..95ef1bdfea 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Refactoring/Refactoring_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Refactoring/Refactoring_spec.ts @@ -183,6 +183,6 @@ describe("Validate JS Object Refactoring does not affect the comments & variable action: "Delete", entityType: entityItems.Api, }); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/SetProperty/SetOptions_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/SetProperty/SetOptions_Spec.ts new file mode 100644 index 0000000000..b6b95b9c37 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/SetProperty/SetOptions_Spec.ts @@ -0,0 +1,386 @@ +import { + entityExplorer, + jsEditor, + agHelper, + locators, + propPane, + draggableWidgets, + deployMode, + debuggerHelper, + apiPage, + dataManager, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Widget Property Setters - Part III - Tc #2409 - Validates SetOptions", () => { + before(() => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2, 300); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 300, 200); + entityExplorer.SelectEntityByName("Input1"); + propPane.UpdatePropertyFieldValue("Default value", "{{Select1.options}}"); + }); + + it("1. Set Widget property to unaccepted values & verify debug error", () => { + //SetOptions to not acceptable value - Boolean + jsEditor.CreateJSObject( + `export default { + myFun1 () { + Select1.setOptions(false); + } + }`, + { + completeReplace: true, + }, + ); + jsEditor.RunJSObj(); + entityExplorer.SelectEntityByName("Page1"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.eq("false"); + }); + debuggerHelper.AssertDebugError( + "Default value is missing in options. Please update the value.", + "", + true, + false, + ); + + //SetOptions to not acceptable value - Numeric + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + myFun1 () { + Select1.setOptions(1234); + } + }`, + false, + ); + jsEditor.RunJSObj(); + entityExplorer.SelectEntityByName("Page1"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.eq("1234"); + }); + debuggerHelper.AssertDebugError( + "Default value is missing in options. Please update the value.", + "", + false, + false, + ); + + //SetOptions to not acceptable value - String + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + myFun1 () { + Select1.setOptions('fdfjhgf7'); + } + }`, + false, + ); + jsEditor.RunJSObj(); + entityExplorer.SelectEntityByName("Page1"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.eq("fdfjhgf7"); + }); + debuggerHelper.AssertDebugError( + "Default value is missing in options. Please update the value.", + "", + false, + false, + ); + + //SetOptions to not acceptable value - undefined + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + myFun1 () { + Select1.setOptions(undefined); + } + }`, + false, + ); + jsEditor.RunJSObj(); + entityExplorer.SelectEntityByName("Page1"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.eq("fdfjhgf7"); + }); + debuggerHelper.AssertDebugError( + "Default value is missing in options. Please update the value.", + "", + false, + false, + ); + + //SetOptions to not acceptable value - null + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + myFun1 () { + Select1.setOptions(null); + } + }`, + false, + ); + jsEditor.RunJSObj(); + entityExplorer.SelectEntityByName("Page1"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.be.empty; + }); + debuggerHelper.AssertDebugError( + "Default value is missing in options. Please update the value.", + "", + false, + false, + ); + + //unabel to set +ve value to setOptions: + // {{JSObject1.myFun1.data.map((item)=>{return{ + // label: item.name, + // value: item.email } })}} + // deployMode.DeployApp(); + }); + + it("2. Update 'setOptions' property By JS function & By action selector", () => { + entityExplorer.SelectEntityByName("Select1"); + propPane.EnterJSContext("Source Data", ""); // By JS function + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj(`export default { + myFun1 () { + Select1.setOptions([{label: 'monday', value: 'weekday'}]) + } + }`); + jsEditor.RunJSObj(); + entityExplorer.SelectEntityByName("Page1"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.include("monday").and.to.include("weekday"); + }); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 300, 300); + propPane.EnterJSContext("onClick", "{{JSObject1.myFun1()}}"); // By action selector + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj(`export default { + myFun1 () { + Select1.setOptions([{label: 'monday', value: 'weekday', code: '1'}]) + } + }`); + deployMode.DeployApp(); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.eq("[]"); + }); + agHelper.ClickButton("Submit"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val) + .to.include("monday") + .and.to.include("weekday") + .and.to.include("1"); + }); + deployMode.NavigateBacktoEditor(); + }); + + it("3. Update 'setOptions' property - during onPage load", () => { + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EnableDisableAsyncFuncSettings("myFun1", true, false); //for on page load execution + deployMode.DeployApp(); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val) + .to.include("monday") + .and.to.include("weekday") + .and.to.include("1"); + }); + deployMode.NavigateBacktoEditor(); + }); + + it("4. Update 'setOptions' property - during onPage load - via Promise", () => { + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj(`export default { + myFun1 () { + return new Promise((resolve,reject)=>{ + Select1.setOptions([{label: 'monday', value: 'weekday'}]) + }) + } + }`); + deployMode.DeployApp(); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val) + .to.include("monday") + .and.to.include("weekday") + .and.not.to.include("1"); + }); + deployMode.NavigateBacktoEditor(); + }); + + it("5. Update 'setOptions' property - during onPage load - via CallBack", () => { + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, + ); + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj(`export default { + async myFunc1 () { + await Api1.run(() => {Select1.setOptions([ + { + "label": "Api callback", + "value": "Api callback" + } + ])}, () => {showAlert('unable to run API')}); + } + }`); + jsEditor.EnableDisableAsyncFuncSettings("myFunc1", true, false); //for on page load execution, since sync function is updated to async + deployMode.DeployApp(); + agHelper.Sleep(2000); //for call to finish for CI runs + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.include("Api callback"); + }); + deployMode.NavigateBacktoEditor(); + }); + + it("6. Update 'setOptions' property - during onPage load - via contcat", () => { + entityExplorer.SelectEntityByName("Select1"); + propPane.EnterJSContext( + "Source Data", + `[ + { + "name": "monday", + "code": "Weekday" + } + ]`, + ); // By JS function + entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 300, 400); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 300, 500); + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj(`export default { + myFunc1 () { + Select3.setOptions(Select1.options.concat(Select2.options)); + } + }`); + jsEditor.EnableDisableAsyncFuncSettings("myFunc1", true, false); //for on page load execution, since sync function is updated to async + entityExplorer.SelectEntityByName("Input1"); + propPane.UpdatePropertyFieldValue("Default value", "{{Select3.options}}"); + deployMode.DeployApp(); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val) + .to.include("monday") + .and.to.include("Blue") + .and.to.include("Red") + .and.to.include("Green"); + }); + deployMode.NavigateBacktoEditor(); + }); + + it("7. Update 'setOptions' property - via SetTimeout framework function", () => { + entityExplorer.SelectEntityByName("Input1"); + propPane.UpdatePropertyFieldValue("Default value", "{{Select1.options}}"); + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj(`export default { + myFun1() { + let localValue = {"label": 'local label', "value": 'local value'}; + setTimeout(() => {Select1.setOptions(localValue)}, 1000); + } + }`); + jsEditor.EnableDisableAsyncFuncSettings("myFun1", false, false); //for on page load execution + deployMode.DeployApp(); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.contain("monday"); + }); + agHelper.ClickButton("Submit"); + agHelper.Sleep(); //settimeout timer! + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).to.include("local label").and.to.include("local value"); + }); + deployMode.NavigateBacktoEditor(); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/WidgetPropertySetters_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/SetProperty/WidgetPropertySetters1_spec.ts similarity index 95% rename from app/client/cypress/e2e/Regression/ClientSide/Widgets/WidgetPropertySetters_spec.ts rename to app/client/cypress/e2e/Regression/ClientSide/SetProperty/WidgetPropertySetters1_spec.ts index ad56004d9d..dfeb14d87c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/WidgetPropertySetters_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/SetProperty/WidgetPropertySetters1_spec.ts @@ -155,8 +155,10 @@ describe("Linting warning for setter methods", function () { propPane.TypeTextIntoField("Label", "{{Button1.setLabel('Hello')}}"); //Mouse hover to exact warning message + agHelper.AssertElementVisibility(locators._lintErrorElement); agHelper.HoverElement(locators._lintErrorElement); agHelper.AssertContains("Data fields cannot execute async code"); + agHelper.Sleep(); //Create a JS object jsEditor.CreateJSObject( @@ -175,10 +177,12 @@ describe("Linting warning for setter methods", function () { }, ); + agHelper.AssertElementVisibility(locators._lintErrorElement); agHelper.HoverElement(locators._lintErrorElement); agHelper.AssertContains( - "Direct mutation of widget properties aren't supported. Use Button1.setVisibility(value) instead.", + "Direct mutation of widget properties is not supported. Use Button1.setVisibility(value) instead.", ); + agHelper.Sleep(); //Add myFun1 to onClick entityExplorer.SelectEntityByName("Button1"); @@ -187,5 +191,6 @@ describe("Linting warning for setter methods", function () { agHelper.AssertContains( "Found an action invocation during evaluation. Data fields cannot execute actions.", ); + agHelper.Sleep(); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/SetProperty/WidgetPropertySetters2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/SetProperty/WidgetPropertySetters2_spec.ts new file mode 100644 index 0000000000..111ff48607 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/SetProperty/WidgetPropertySetters2_spec.ts @@ -0,0 +1,245 @@ +import { + entityExplorer, + jsEditor, + agHelper, + locators, + propPane, + draggableWidgets, + deployMode, + apiPage, + dataManager, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Widget Property Setters - Part II - Tc #2409", () => { + it("1. Bug 25287 - CurrencyInput does not update value when set using CurrencyInput.text", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.CURRENCY_INPUT); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 300, 200); + + //Create a JS object + jsEditor.CreateJSObject( + `export default { + myFun1 () { + storeValue('currencyVal', 99) + CurrencyInput1.setValue(appsmith.store.currencyVal)} + }`, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }, + ); + entityExplorer.SelectEntityByName("Button1"); + propPane.EnterJSContext("onClick", "{{JSObject1.myFun1()}}"); + deployMode.DeployApp(); + agHelper.ClickButton("Submit"); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.CURRENCY_INPUT) + + " " + + locators._input, + "val", + "99", + ); + }); + + it("2. Update Visible property via JS function - using appmsith store", () => { + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + myFun1 () { + appsmith.store.currencyVal>90 ? CurrencyInput1.setVisibility(false):CurrencyInput1.setVisibility(true); + } + }`, + false, + ); + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.CURRENCY_INPUT), //Asserting before JS function execution, should be visible + ); + agHelper.ClickButton("Submit"); + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.CURRENCY_INPUT), + ); + }); + + it("3. Update Input value via JS function - using async await - Api call", () => { + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, + ); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2, 300, 300); + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + async myFun1 () { + let local = await Api1.run().then((data)=> data.map((user) => + {return { + name: user.name, + id: user.id, + status: user.status, + } + })); + Input1.setValue(local[5].name); + } + }`, + false, + ); + deployMode.DeployApp(); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).be.empty; + }); + agHelper.ClickButton("Submit"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).not.be.empty; + }); + }); + + it("4. Update Input value via JS Call back function - in Edit mode itself + OnPage load", () => { + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + async myFun1 () { + let local = await Api1.run().then((data)=> data.map((user) => + {return { + name: user.name, + id: user.id, + email: user.email, + } + })); + Input1.setValue(local[5].email); + } + }`, + false, + ); + jsEditor.RunJSObj(); + entityExplorer.SelectEntityByName("Page1"); + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).contains("@"); + }); + + entityExplorer.SelectEntityByName("Input1"); + propPane.UpdatePropertyFieldValue( + "Default value", + "{{appsmith.user.name}}", + ); + deployMode.DeployApp(); //below validates the Page load + agHelper + .GetText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + + " " + + locators._input, + "val", + ) + .then((val) => { + expect(val).not.be.empty; + }); + }); + + it("5. Update Widget property through framework function - Settimeout", () => { + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + async myFun1 () { + setTimeout(()=>{Button1.isVisible ?Button1.setVisibility(false):Button1.setVisibility(true)},2000) + } + }`, + false, + ); + jsEditor.EnableDisableAsyncFuncSettings("myFun1", true, false); + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.BUTTON), //Asserting before setTimeout JS function execution, button is visible + ); + agHelper.Sleep(2000); //waiting for settimeout to execute + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.BUTTON), + ); + }); + + it("6. Verify SetWidget for unsupported properties - setPlaying(Audio widget) property for Button, set property via try/catch block", () => { + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + myFun1 () { + Button1.setPlaying(true); + }, + }`, + false, + ); + agHelper.AssertElementVisibility(locators._lintErrorElement); + agHelper.HoverElement(locators._lintErrorElement); + agHelper.AssertContains(`"setPlaying" doesn't exist in Button1`); + + //try catch block + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + myFun1 () { + try { + Api1.run().then(()=>{ Button1.setVisibility(false)}) + } + catch(e) + { showAlert(e.message) } + }, + }`, + false, + ); + deployMode.DeployApp(); + agHelper.Sleep(3000); //for the Api to run & button to disappear, for CI runs + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.BUTTON), + ); + }); + + it("7.Update set property using mutative values", () => { + entityExplorer.SelectEntityByName("Button1"); + propPane.TogglePropertyState("Visible", "Off"); //due to bug, element state is not altereed when set via settimeout + propPane.TogglePropertyState("Visible", "On"); + entityExplorer.SelectEntityByName("JSObject1"); + jsEditor.EditJSObj( + `export default { + var1: [true,false,true,false], + async myFun1() { + for (let i =0; i<=this.var1.length;i++){ + Input1.setVisibility(this.var1[i]); + } + }, + }`, + false, + ); + jsEditor.EnableDisableAsyncFuncSettings("myFun1", false, false); + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.INPUT_V2), //Asserting before setTimeout JS function execution, Input is visible + ); + agHelper.ClickButton("Submit"); + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.INPUT_V2), + ); + }); + + afterEach(() => { + deployMode.NavigateBacktoEditor(); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesModal_filtering_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesModal_filtering_spec.ts index 41162ac0a4..99be764730 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesModal_filtering_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesModal_filtering_spec.ts @@ -12,6 +12,7 @@ describe("excludeForAirgap", "Bug 17276 - Templates modal filtering", () => { agHelper.GetText(templates.locators._resultsHeader).then((headerText) => { templates.FilterTemplatesByName(NAME_FILTER); + agHelper.Sleep(); if (typeof headerText === "string") { templates.AssertResultsHeaderText(headerText, "not.have.text"); } diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesPage_filtering_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesPage_filtering_spec.ts index 1e788b943e..fd73106449 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesPage_filtering_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/Filtering/TemplatesPage_filtering_spec.ts @@ -38,7 +38,6 @@ describe("excludeForAirgap", "Templates page filtering", () => { .GetText(templates.locators._resultsHeader, "text") .then((headerText) => { templates.FilterTemplatesByName(NAME_FILTER); - agHelper.Sleep(); agHelper.GetNClick(templates.locators._templateCard); agHelper.GetNClick(templates.locators._templateViewGoBack); agHelper.AssertText( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js b/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js index fa17638422..a338d55214 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/ForkTemplateToGitConnectedApp.js @@ -56,7 +56,7 @@ describe("excludeForAirgap", "Fork a template to the current app", () => { cy.commitAndPush(); }); // skipping this test as saving page is taking lot of time - it.skip("2. Bug #17262 On forking template to a child branch of git connected app is throwing Page not found error ", function () { + it("2. Bug #17262 On forking template to a child branch of git connected app is throwing Page not found error ", function () { _.gitSync.CreateGitBranch(branchName, true); cy.get("@gitbranchName").then((branName) => { branchName = branName; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js index 4968bc183f..fe1fa175fa 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js @@ -27,10 +27,7 @@ describe( agHelper.AssertElementExist(template.templateDialogBox); agHelper.AssertElementVisibility(templates.locators._templateCard); agHelper.Sleep(4000); - cy.xpath("//h1[text()='Meeting Scheduler']/parent::div") - .scrollIntoView() - .wait(500) - .click(); + agHelper.GetNClick(template.vehicleMaintenenceApp); agHelper.WaitUntilEleDisappear("//*[text()='Loading template details']"); agHelper.Sleep(); agHelper.CheckForErrorToast( @@ -52,9 +49,14 @@ describe( it("2. Add selected page of template from page section", () => { entityExplorer.AddNewPage("Add page from template"); agHelper.AssertElementVisibility(template.templateDialogBox); - agHelper.Sleep(4000); - cy.xpath("//h1[text()='Meeting Scheduler']").click(); - agHelper.WaitUntilEleDisappear("//*[text()='Loading template details']"); + agHelper.AssertElementVisibility( + templates.locators._templateCard, + true, + 0, + 30000, + ); + agHelper.GetNClick(template.vehicleMaintenenceApp); + //agHelper.WaitUntilEleDisappear("//*[text()='Loading template details']"); cy.wait("@getTemplatePages").should( "have.nested.property", "response.body.responseMeta.status", @@ -80,6 +82,12 @@ describe( //agHelper.RefreshPage(); entityExplorer.AddNewPage("Add page from template"); + agHelper.AssertElementVisibility( + templates.locators._templateCard, + true, + 0, + 30000, + ); agHelper.GetNClick(templates.locators._templateCard); agHelper.Sleep(2000); agHelper.AssertElementVisibility(template.templateViewForkButton); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.js index 9ee00f99a7..9137a564c9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_To_App_spec.js @@ -1,16 +1,19 @@ import widgetLocators from "../../../../locators/Widgets.json"; import template from "../../../../locators/TemplatesLocators.json"; -import * as _ from "../../../../support/Objects/ObjectsCore"; - -let appId, newWorkspaceName; +import { + agHelper, + assertHelper, + deployMode, + entityExplorer, +} from "../../../../support/Objects/ObjectsCore"; describe("excludeForAirgap", "Fork a template to the current app", () => { afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); // Closes template dialog if it is already open - useful for retry cy.get("body").then(($ele) => { if ($ele.find(template.templateDialogBox).length) { @@ -25,7 +28,7 @@ describe("excludeForAirgap", "Fork a template to the current app", () => { it("1. Fork a template to the current app + Bug 17477", () => { cy.wait(3000); - _.entityExplorer.AddNewPage("Add page from template"); + entityExplorer.AddNewPage("Add page from template"); // Commented out below code as fetch template call is not going through when template dialog is closed // cy.wait("@fetchTemplate").should( // "have.nested.property", @@ -38,7 +41,7 @@ describe("excludeForAirgap", "Fork a template to the current app", () => { .scrollIntoView() .wait(500) .click(); - _.agHelper.CheckForErrorToast("INTERNAL_SERVER_ERROR"); + agHelper.CheckForErrorToast("INTERNAL_SERVER_ERROR"); cy.wait(6000); cy.get("body").then(($ele) => { if ($ele.find(widgetLocators.toastAction).length <= 0) { @@ -51,14 +54,14 @@ describe("excludeForAirgap", "Fork a template to the current app", () => { "contain", "template added successfully", ); - _.assertHelper.AssertNetworkStatus("updateLayout"); + assertHelper.AssertNetworkStatus("updateLayout"); // [Bug]: Getting 'Resource not found' error on deploying template #17477 - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.get(".t--page-switch-tab") .contains("1 Track Applications") .click({ force: true }); cy.wait(4000); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); cy.wait(2000); }); @@ -79,7 +82,7 @@ describe("excludeForAirgap", "Fork a template to the current app", () => { cy.wait(5000); cy.get(template.templateDialogBox).should("be.visible"); cy.xpath("//h1[text()='Applicant Tracker-test']").click(); - _.agHelper.CheckForErrorToast("INTERNAL_SERVER_ERROR"); + agHelper.CheckForErrorToast("INTERNAL_SERVER_ERROR"); cy.wait("@getTemplatePages").should( "have.nested.property", "response.body.responseMeta.status", @@ -95,10 +98,10 @@ describe("excludeForAirgap", "Fork a template to the current app", () => { "response.body.responseMeta.status", 200, ); - cy.get(widgetLocators.toastAction, { timeout: 40000 }).should( + cy.get(widgetLocators.toastAction, { timeout: 50000 }).should( "contain", "template added successfully", ); - _.assertHelper.AssertNetworkStatus("updateLayout"); + assertHelper.AssertNetworkStatus("updateLayout"); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_spec.js index 118a436570..8c1391574b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_spec.js @@ -17,8 +17,10 @@ describe("excludeForAirgap", "Fork a template to an workspace", () => { cy.get(templateLocators.templateViewForkButton).click(); } }); - cy.get(templateLocators.dialogForkButton).click(); - + _.agHelper.WaitUntilEleAppear( + `div[role="dialog"]:has(` + templateLocators.dialogForkButton + `)`, + ); + cy.get(templateLocators.dialogForkButton).click({ force: true }); cy.get(commonlocators.canvas, { timeout: 30000 }).should("be.visible"); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js index 99d95e50a8..36d2e0a9e3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Basic_spec.js @@ -1,7 +1,12 @@ const commonlocators = require("../../../../locators/commonlocators.json"); const widgetsPage = require("../../../../locators/Widgets.json"); const publish = require("../../../../locators/publishWidgetspage.json"); -import * as _ from "../../../../support/Objects/ObjectsCore"; +import { + agHelper, + appSettings, + deployMode, + entityExplorer, +} from "../../../../support/Objects/ObjectsCore"; const containerShadowElement = `${widgetsPage.containerWidget}`; @@ -19,13 +24,13 @@ describe("App Theming funtionality", function () { themesSection(sectionName, themeName) + "/following-sibling::button"; it("1. Checks if theme can be changed to one of the existing themes", function () { - _.appSettings.OpenAppSettings(); - _.appSettings.GoToThemeSettings(); + appSettings.OpenAppSettings(); + appSettings.GoToThemeSettings(); cy.get(commonlocators.changeThemeBtn).click({ force: true }); - + cy.assertPageSave(); // select a theme cy.get(commonlocators.themeCard).last().click({ force: true }); - + cy.assertPageSave(); // check for alert cy.get(`${commonlocators.themeCard}`) .last() @@ -51,17 +56,17 @@ describe("App Theming funtionality", function () { it("2. Checks if theme can be edited", function () { cy.get(commonlocators.selectThemeBackBtn).click({ force: true }); - _.appSettings.ClosePane(); + appSettings.ClosePane(); // drop a button & container widget and click on body - _.entityExplorer.NavigateToSwitcher("Widgets"); + entityExplorer.NavigateToSwitcher("Widgets"); cy.dragAndDropToCanvas("buttonwidget", { x: 200, y: 200 }); cy.dragAndDropToCanvas("containerwidget", { x: 200, y: 50 }); cy.assertPageSave(); cy.get("canvas").first(0).trigger("click", { force: true }); - _.appSettings.OpenAppSettings(); - _.appSettings.GoToThemeSettings(); + appSettings.OpenAppSettings(); + appSettings.GoToThemeSettings(); //Click the back button //Commenting below since expanded by default //cy.get(commonlocators.selectThemeBackBtn).click({ force: true }); @@ -73,7 +78,7 @@ describe("App Theming funtionality", function () { // change app border radius cy.get(commonlocators.themeAppBorderRadiusBtn).eq(1).click({ force: true }); - + cy.assertPageSave(); // check if border radius is changed on button cy.get(commonlocators.themeAppBorderRadiusBtn) .eq(1) @@ -86,7 +91,7 @@ describe("App Theming funtionality", function () { ); // publish the app - // _.deployMode.DeployApp(); + // deployMode.DeployApp(); cy.get(widgetsPage.widgetBtn).should( "have.css", "border-radius", @@ -111,8 +116,10 @@ describe("App Theming funtionality", function () { }); //Change the background color: - cy.get("[data-testid='theme-backgroundColor']").click({ force: true }); - cy.wait(500); + //cy.get("[data-testid='theme-backgroundColor']").click({ force: true }); + agHelper.GetNClick("[data-testid='theme-backgroundColor']"); + agHelper.AssertAutoSave(); + cy.get(widgetsPage.colorPickerV2Popover).click({ force: true }).click(); cy.get(widgetsPage.colorPickerV2Color) .first() @@ -141,9 +148,8 @@ describe("App Theming funtionality", function () { //Change the font //Commenting below since expanded by default //cy.contains("Font").click({ force: true }); - cy.get(".rc-select-selection-search-input").then(($elem) => { - cy.get($elem).click({ force: true }); - cy.wait(250); + agHelper.GetNClick(".rc-select-selection-search-input").then(($elem) => { + agHelper.GetNClick($elem); cy.get(".rc-virtual-list-holder div") .children() .eq(2) @@ -166,41 +172,31 @@ describe("App Theming funtionality", function () { .first() .find("button") .click({ force: true }); - // .then(($elem) => { - // cy.get(`${$elem} button`).click({ force: true }); - // }) - cy.wait(300); + agHelper.AssertAutoSave(); //Click on save theme dropdown option cy.contains("Save theme").click({ force: true }); - cy.wait(200); - //Type the name of the theme: - cy.get("input[placeholder='My theme']").type("testtheme"); - + agHelper.TypeText("input[placeholder='My theme']", "testtheme"); //Click on save theme button - cy.get("button[type='submit']").click({ force: true }); - - cy.wait(200); - cy.get(commonlocators.toastMsg).contains("Theme testtheme saved"); - _.appSettings.ClosePane(); + agHelper.ClickButton("Save theme"); + agHelper.ValidateToastMessage("Theme testtheme saved"); + appSettings.ClosePane(); }); it("4. Verify Save Theme after changing all properties & widgets conform to the selected theme", () => { - _.entityExplorer.NavigateToSwitcher("Widgets"); + entityExplorer.NavigateToSwitcher("Widgets"); cy.dragAndDropToCanvas("iconbuttonwidget", { x: 200, y: 300 }); cy.assertPageSave(); cy.get("canvas").first(0).trigger("click", { force: true }); - _.appSettings.OpenAppSettings(); - _.appSettings.GoToThemeSettings(); + appSettings.OpenAppSettings(); + appSettings.GoToThemeSettings(); //#region Change Font & verify widgets: - // cy.contains("Font") - // .click({ force: true }) - // .wait(200);//Commenting below since expanded by default - cy.get(".rc-select-selection-search-input").then(($elem) => { + + agHelper.GetNClick(".rc-select-selection-search-input").then(($elem) => { cy.get($elem).click({ force: true }); cy.wait(250); cy.get(".rc-virtual-list-holder div") @@ -221,13 +217,6 @@ describe("App Theming funtionality", function () { }); }); - //#endregion - - //#region Change Color & verify widgets: - //Change the primary color: - // cy.contains("Color") - // .click({ force: true }) - // .wait(200); cy.get(widgetsPage.colorPickerV2Popover).click({ force: true }).click(); cy.get(widgetsPage.colorPickerV2Color) .eq(-15) @@ -260,12 +249,6 @@ describe("App Theming funtionality", function () { ); }); - //#endregion - - //#region Change Border radius & verify widgets - // cy.contains("Border") - // .click({ force: true }) - // .wait(200); cy.get(commonlocators.themeAppBorderRadiusBtn).eq(2).click({ force: true }); cy.get(`${commonlocators.themeAppBorderRadiusBtn}`) .eq(2) @@ -283,8 +266,6 @@ describe("App Theming funtionality", function () { ); }); - //#endregion - //#region Change the shadow & verify widgets cy.get("[data-value='L']").eq(1).click({ force: true }); cy.get("[data-value='L']") @@ -298,8 +279,6 @@ describe("App Theming funtionality", function () { ); }); - //#endregion - //#region Click on dropDown elipses cy.contains("Theme properties") .closest("div") @@ -308,7 +287,6 @@ describe("App Theming funtionality", function () { .find("button") .click({ force: true }); cy.wait(300); - //#endregion //Click on save theme dropdown option & close it cy.contains("Save theme").click({ force: true }); @@ -338,16 +316,14 @@ describe("App Theming funtionality", function () { cy.contains("Save theme").click({ force: true }); cy.wait(200); //Type the name of the theme: - cy.get("input[placeholder='My theme']").type("testtheme"); + agHelper.TypeText("input[placeholder='My theme']", "testtheme"); cy.contains("Name must be unique"); cy.get("input[placeholder='My theme']").clear().type("VioletYellowTheme"); //Click on save theme button - cy.xpath("//span[text()='Save theme']/parent::div").click({ force: true }); - - cy.wait(200); - cy.get(commonlocators.toastMsg).contains("Theme VioletYellowTheme saved"); + agHelper.ClickButton("Save theme"); + agHelper.ValidateToastMessage("Theme VioletYellowTheme saved"); }); it("5. Verify Themes exists under respective section when ChangeTheme button is cicked in properties with Apply Theme & Trash as applicable", () => { @@ -387,25 +363,10 @@ describe("App Theming funtionality", function () { cy.xpath(applyTheme("Featured themes", "Pampas")).should("exist"); cy.xpath(themesDeletebtn("Featured themes", "Pampas")).should("not.exist"); - - // cy.contains("Featured themes") - // .siblings() - // .find(".t--theme-card") - // .siblings() - // .should("contain.text", "Rounded").siblings() - // .contains('Apply Theme'); }); it("6. Verify the custom theme can be deleted", () => { - //Check if the saved theme is present under 'Yours Themes' section - // cy.contains("Your themes") - // .siblings() - // .find(".t--theme-card") - // .parent() - // .find("button").eq(0) - // .click({ force: true }); - // cy.wait(200); - + //Delete the created theme cy.xpath(themesDeletebtn("Your themes", "testtheme")) .click({ force: true }) .wait(200); @@ -428,11 +389,13 @@ describe("App Theming funtionality", function () { cy.xpath(themesDeletebtn("Your themes", "testtheme")) .click({ force: true }) .wait(200); - cy.contains("Delete").click({ force: true }); + agHelper.ClickButton("Delete"); + // cy.contains("Delete").click({ force: true }); //check for delete alert - cy.wait(500); - cy.get(commonlocators.toastMsg).contains("Theme testtheme deleted"); + // cy.wait(500); + agHelper.ValidateToastMessage("Theme testtheme deleted"); + //cy.get(commonlocators.toastMsg).contains("Theme testtheme deleted"); cy.xpath(applyTheme("Your themes", "testtheme")).should("not.exist"); }); @@ -687,7 +650,7 @@ describe("App Theming funtionality", function () { }); it("8. Verify widgets conform to the selected theme in Publish mode", () => { - _.deployMode.DeployApp(); + deployMode.DeployApp(); //cy.wait(4000); //for theme to settle @@ -715,11 +678,11 @@ describe("App Theming funtionality", function () { cy.get(widgetsPage.widgetBtn).should("have.css", "box-shadow", "none"); //Shadow cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); //Shadow - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); it("9. Verify Adding new Individual widgets & it can change Color, Border radius, Shadow & can revert [Color/Border Radius] to already selected theme", () => { - _.entityExplorer.NavigateToSwitcher("Widgets"); + entityExplorer.NavigateToSwitcher("Widgets"); cy.dragAndDropToCanvas("buttonwidget", { x: 200, y: 400 }); //another button widget cy.assertPageSave(); cy.moveToStyleTab(); @@ -781,9 +744,8 @@ describe("App Theming funtionality", function () { "none", ); - cy.assertPageSave(); - cy.wait(2000); - _.deployMode.DeployApp(); + agHelper.AssertAutoSave(); + deployMode.DeployApp(); //Verify Background color cy.get(".t--widget-buttonwidget:nth-child(4) button").should( @@ -831,11 +793,11 @@ describe("App Theming funtionality", function () { "none", ); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); //Resetting back to theme - _.entityExplorer.NavigateToSwitcher("Explorer"); - _.entityExplorer.ExpandCollapseEntity("Widgets"); //to expand widgets - _.entityExplorer.SelectEntityByName("Button2"); + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.ExpandCollapseEntity("Widgets"); //to expand widgets + entityExplorer.SelectEntityByName("Button2"); cy.moveToStyleTab(); cy.get(".t--property-control-buttoncolor .reset-button").then(($elem) => { $elem[0].removeAttribute("display: none"); @@ -858,7 +820,7 @@ describe("App Theming funtionality", function () { ); //the new widget with reverted styles also conforming to theme - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.wait(4000); //for theme to settle cy.get("body").should("have.css", "font-family", "Inter, sans-serif"); //Font @@ -914,14 +876,14 @@ describe("App Theming funtionality", function () { ); //Since Shadow revert option does not exixts cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); //Shadow - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); it("10. Verify Chainging theme should not affect Individual widgets with changed Color, Border radius, Shadow & can revert to newly selected theme", () => { cy.get("canvas").first(0).trigger("click", { force: true }); - _.appSettings.OpenAppSettings(); - _.appSettings.GoToThemeSettings(); + appSettings.OpenAppSettings(); + appSettings.GoToThemeSettings(); cy.get(commonlocators.changeThemeBtn).click({ force: true }); @@ -931,9 +893,9 @@ describe("App Theming funtionality", function () { .wait(2000); //Change individual widget properties for Button1 - _.entityExplorer.NavigateToSwitcher("Explorer"); - _.entityExplorer.ExpandCollapseEntity("Widgets"); //to expand widgets - _.entityExplorer.SelectEntityByName("Button1"); + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.ExpandCollapseEntity("Widgets"); //to expand widgets + entityExplorer.SelectEntityByName("Button1"); cy.moveToStyleTab(); //Change Color & verify @@ -998,7 +960,7 @@ describe("App Theming funtionality", function () { cy.assertPageSave(); //Add deploy mode verification here also! - _.deployMode.DeployApp(); + deployMode.DeployApp(); //Verify Background color cy.get(".t--widget-button1 button").should( @@ -1045,11 +1007,11 @@ describe("App Theming funtionality", function () { "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", ); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); //Resetting back to theme - _.entityExplorer.NavigateToSwitcher("Explorer"); - _.entityExplorer.ExpandCollapseEntity("Widgets"); //to expand widgets - _.entityExplorer.SelectEntityByName("Button1"); + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.ExpandCollapseEntity("Widgets"); //to expand widgets + entityExplorer.SelectEntityByName("Button1"); cy.moveToStyleTab(); cy.get(".t--property-control-buttoncolor .reset-button").then(($elem) => { $elem[0].removeAttribute("display: none"); @@ -1073,7 +1035,7 @@ describe("App Theming funtionality", function () { ); //the new widget with reverted styles also conforming to theme - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.wait(4000); //for theme to settle cy.get("body").should("have.css", "font-family", "Rubik, sans-serif"); //Font for Rounded theme @@ -1130,6 +1092,6 @@ describe("App Theming funtionality", function () { ); //Since Shadow revert option does not exixts cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); //Shadow - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_Default_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_Default_spec.js deleted file mode 100644 index 13f4798909..0000000000 --- a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_Default_spec.js +++ /dev/null @@ -1,88 +0,0 @@ -import { - draggableWidgets, - entityExplorer, - appSettings, -} from "../../../../support/Objects/ObjectsCore"; - -const widgetsPage = require("../../../../locators/Widgets.json"); -const commonlocators = require("../../../../locators/commonlocators.json"); -const formWidgetsPage = require("../../../../locators/FormWidgets.json"); -const themelocator = require("../../../../locators/ThemeLocators.json"); - -let themeBackgroudColor; - -describe.skip("Theme validation for default data", function () { - it("1. Drag and drop form widget and validate Default color/font/shadow/border and list of font validation", function () { - entityExplorer.DragDropWidgetNVerify(draggableWidgets.FORM, 300, 80); - agHelper.GetNClick(locators._canvas); - appSettings.OpenAppSettings(); - appSettings.GoToThemeSettings(); - //Border validation - //cy.contains("Border").click({ force: true }); - cy.get(themelocator.border).should("have.length", "3"); - cy.borderMouseover(0, "none"); - cy.borderMouseover(1, "M"); - cy.borderMouseover(2, "L"); - cy.contains("Border").click({ force: true }); - - //Shadow validation - //cy.contains("Shadow").click({ force: true }); - cy.wait(2000); - cy.contains("Shadow").click({ force: true }); - - //Font - //cy.contains("Font").click({ force: true }); - // cy.get("span[name='expand-more']").then(($elem) => { - // cy.get($elem).click({ force: true }); - // cy.wait(250); - - cy.get(themelocator.fontsSelected) - //.eq(10) - .should("have.text", "Nunito Sans"); - //}); - cy.contains("Font").click({ force: true }); - - //Color - //cy.contains("Color").click({ force: true }); - cy.wait(2000); - cy.colorMouseover(0, "Primary color"); - cy.validateColor("Primary", "#553DE9"); - cy.colorMouseover(1, "Background color"); - cy.validateColor("Background", "#F8FAFC"); - appSettings.ClosePane(); - }); - - it("2. Validate Default Theme change across application", function () { - cy.get(formWidgetsPage.formD).click(); - cy.widgetText( - "FormTest", - formWidgetsPage.formWidget, - widgetsPage.widgetNameSpan, - ); - cy.moveToStyleTab(); - cy.get(widgetsPage.backgroundcolorPickerNew).first().click({ force: true }); - cy.get("[style='background-color: rgb(21, 128, 61);']").last().click(); - cy.wait(2000); - cy.get(formWidgetsPage.formD) - .should("have.css", "background-color") - .and("eq", "rgb(21, 128, 61)"); - cy.get("#canvas-selection-0").click({ force: true }); - appSettings.OpenAppSettings(); - appSettings.GoToThemeSettings(); - //Change the Theme - cy.get(commonlocators.changeThemeBtn).click({ force: true }); - cy.get(".cursor-pointer:contains('Applied theme')").click({ force: true }); - cy.get(".t--theme-card main > main") - .first() - .invoke("css", "background-color") - .then((CurrentBackgroudColor) => { - cy.get(".bp3-button:contains('Submit')") - .last() - .invoke("css", "background-color") - .then((selectedBackgroudColor) => { - expect(CurrentBackgroudColor).to.equal(selectedBackgroudColor); - themeBackgroudColor = CurrentBackgroudColor; - }); - }); - }); -}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js index 4b02dcb51a..f8e555f67b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js @@ -88,8 +88,8 @@ describe("Theme validation usecase for multi-select widget", function () { appSettings.ClosePane(); }); + //Skipping due to mentioned bug it.skip("2. Publish the App and validate Font across the app + Bug 15007", function () { - //Skipping due to mentioned bug deployMode.DeployApp(); cy.get(".rc-select-selection-item > .rc-select-selection-item-content") .first() diff --git a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/AppPageLayout_spec.js b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/AppPageLayout_spec.js index 4bca57f843..3d56fe1b21 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/AppPageLayout_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/AppPageLayout_spec.js @@ -1,11 +1,11 @@ import homePage from "../../../../locators/HomePage"; import * as _ from "../../../../support/Objects/ObjectsCore"; -describe.skip("Visual regression tests", () => { +describe("Visual regression tests", () => { // for any changes in UI, update the screenshot in snapshot folder, to do so: // 1. Delete the required screenshot which you want to update. // 2. Run test in headless mode with any browser - // command: "npx cypress run --spec cypress/e2e/Regression_TestSuite/ClientSideTests/VisualTests/AppPageLayout_spec.js --browser chrome" + // command: "npx cypress run --spec cypress/e2e/Regression/ClientSide/VisualTests/AppPageLayout_spec.js --browser chrome" // 3. New screenshot will be generated in the snapshot folder. it("1. Layout validation for app page in edit mode", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/DatasourcePageLayout_spec.js b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/DatasourcePageLayout_spec.js index d8f1aa6006..af4b55b064 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/DatasourcePageLayout_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/DatasourcePageLayout_spec.js @@ -1,6 +1,6 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; -describe.skip("Visual tests for datasources", () => { +describe("Visual tests for datasources", () => { // for any changes in UI, update the screenshot in snapshot folder, to do so: // 1. Delete the required screenshot which you want to update. // 2. Run test in headless mode with any browser diff --git a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorComment_spec.js b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorComment_spec.js index 9a450fafa1..292e091c92 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorComment_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorComment_spec.js @@ -3,7 +3,7 @@ import { ObjectsRegistry } from "../../../../support/Objects/Registry"; let jsEditor = ObjectsRegistry.JSEditor, agHelper = ObjectsRegistry.AggregateHelper; -describe.skip("JSEditor Comment - Visual tests", () => { +describe("JSEditor Comment - Visual tests", () => { it("1. comments code on the editor", () => { jsEditor.CreateJSObject( `export default { diff --git a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js index 199f556052..f56dba8386 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js @@ -8,10 +8,12 @@ import { dataSources, } from "../../../../support/Objects/ObjectsCore"; -describe.skip("JSEditor Indendation - Visual tests", () => { +describe("JSEditor Indendation - Visual tests", () => { it("6. TC 1933 - jSEditor prettify verification on cloned application", () => { - const appname = localStorage.getItem("AppName"); - _.jsEditor.CreateJSObject( + const appName = localStorage.getItem("appName"); + const workspaceName = localStorage.getItem("workspaceName"); + + jsEditor.CreateJSObject( `export default { myFun1: () => { console.log("hi"); @@ -56,11 +58,13 @@ myFun2: async () => { cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify6"); // taking a snap after clicking inside the editor to make sure prettify has not reverted - _.agHelper.GetNClick(_.jsEditor._lineinJsEditor(26)); + agHelper.Sleep(110); + agHelper.GetNClick(jsEditor._lineinJsEditor(26)); cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify6"); homePage.NavigateToHome(); - homePage.ForkApplication(appname); + homePage.FilterApplication(workspaceName); + homePage.ForkApplication(appName); entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.SelectEntityByName("JSObject1", "Queries/JS"); cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify6"); @@ -113,7 +117,8 @@ myFun2: async () => { cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify7"); // taking a snap after clicking inside the editor to make sure prettify has not reverted - _.agHelper.GetNClick(_.jsEditor._lineinJsEditor(26)); + agHelper.Sleep(110); + agHelper.GetNClick(jsEditor._lineinJsEditor(26)); cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify7"); entityExplorer.ClonePage("Page1"); @@ -206,7 +211,8 @@ myFun2: async () => { cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify2"); // taking a snap after clicking inside the editor to make sure prettify has not reverted - _.agHelper.GetNClick(_.jsEditor._lineinJsEditor(26)); + agHelper.Sleep(110); + agHelper.GetNClick(jsEditor._lineinJsEditor(26)); cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify2"); // click run button and take a snap to make sure prettify did not revert @@ -311,7 +317,8 @@ myFun2: async () => { cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify4"); // taking a snap after clicking inside the editor to make sure prettify has not reverted - _.agHelper.GetNClick(_.jsEditor._lineinJsEditor(26)); + agHelper.Sleep(110); + agHelper.GetNClick(jsEditor._lineinJsEditor(26)); cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterPrettify4_1"); // click run button and take a snap to make sure prettify did not revert diff --git a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorSaveAndAutoIndent_spec.js b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorSaveAndAutoIndent_spec.js index b18471b0a9..335d92f05d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorSaveAndAutoIndent_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/JSEditorSaveAndAutoIndent_spec.js @@ -1,6 +1,6 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; -describe.skip("JS Editor Save and Auto-indent: Visual tests", () => { +describe("JS Editor Save and Auto-indent: Visual tests", () => { it("1. Auto indents and saves the code when Ctrl/Cmd+s is pressed", () => { _.jsEditor.CreateJSObject( `export default { @@ -49,6 +49,7 @@ myFun2: async () => { _.agHelper.AssertAutoSave(); // taking a snap after clicking inside the editor to make sure prettify has not reverted + _.agHelper.Sleep(110); _.agHelper.GetNClick(_.jsEditor._lineinJsEditor(25)); cy.get("div.CodeMirror").matchImageSnapshot("jsObjAfterSaveAndPrettify"); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/WidgetsLayout_spec.js b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/WidgetsLayout_spec.js index b9d25e41f4..19a9ebafde 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/VisualTests/WidgetsLayout_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/VisualTests/WidgetsLayout_spec.js @@ -1,4 +1,4 @@ -describe.skip("Visual regression tests", () => { +describe("Visual regression tests", () => { // for any changes in UI, update the screenshot in snapshot folder, to do so: // 1. Delete the required screenshot which you want to update // 2. Run test in headless mode with chrome (to maintain same resolution in CI) diff --git a/app/client/cypress/e2e/Regression/ClientSide/Walkthrough/BindingSchemaWidget_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Walkthrough/BindingSchemaWidget_Spec.ts new file mode 100644 index 0000000000..ec4f3e5bb6 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Walkthrough/BindingSchemaWidget_Spec.ts @@ -0,0 +1,52 @@ +import { + agHelper, + dataSources, + propPane, +} from "../../../../support/Objects/ObjectsCore"; +import { addIndexedDBKey } from "../../../../support/commands"; +import { + USER_SIGN_UP_INDEX_KEY, + WALKTHROUGH_TEST_PAGE, +} from "../../../../support/Constants"; +import { Widgets } from "../../../../support/Pages/DataSources"; + +let datasourceName; +describe(`${WALKTHROUGH_TEST_PAGE} : Walkthrough test for schema on action page`, () => { + before(() => { + dataSources.CreateDataSource("Postgres"); + cy.get("@dsName").then(($dsName) => { + datasourceName = $dsName; + }); + addIndexedDBKey(USER_SIGN_UP_INDEX_KEY, { + [Cypress.env("USERNAME")]: Date.now(), + }); + }); + + it("1. Schema walkthrough should appear", () => { + dataSources.CreateQueryAfterDSSaved("select * from users limit 10"); + agHelper.WaitUntilEleAppear(agHelper._walkthroughOverlay); + agHelper.AssertElementExist( + agHelper._walkthroughOverlayTitle("Query data fast"), + ); + agHelper.GetNClick(agHelper._walkthroughOverlayClose); + }); + + it("2. Binding walkthrough should appear", () => { + dataSources.RunQuery(); + agHelper.WaitUntilEleAppear(agHelper._walkthroughOverlay); + agHelper.AssertElementExist( + agHelper._walkthroughOverlayTitle("Display your data"), + ); + agHelper.GetNClick(agHelper._walkthroughOverlayClose); + }); + + it("3. Widget walkthrough should appear", () => { + dataSources.AddSuggestedWidget(Widgets.Table); + agHelper.WaitUntilEleAppear(agHelper._walkthroughOverlay); + agHelper.AssertElementExist( + agHelper._walkthroughOverlayTitle("Widget properties"), + ); + agHelper.GetElement(propPane._paneTitle).contains("Table1"); + agHelper.GetNClick(agHelper._walkthroughOverlayClose); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/Audio_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/Audio1_spec.ts similarity index 95% rename from app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/Audio_spec.ts rename to app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/Audio1_spec.ts index dd056a8ef5..4e15b3e299 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/Audio_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/Audio1_spec.ts @@ -9,13 +9,13 @@ import { const URL = "https://assets.appsmith.com/widgets/birds_chirping.mp3"; -describe("Audio Widget functionality tests", () => { +describe("excludeForAirgap", "Audio Widget functionality tests", () => { before(() => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.AUDIO, 200, 200); }); it("1. Audio widget property verification", () => { entityExplorer.SelectEntityByName("Audio1", "Widgets"); - // assert propertis are present + // assert properties are present propPane.Search("general"); propPane.AssertIfPropertyOrSectionExists("general", "CONTENT"); propPane.Search("data"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/AudioRecorder_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/AudioRecorder1_spec.ts similarity index 99% rename from app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/AudioRecorder_spec.ts rename to app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/AudioRecorder1_spec.ts index 5d3ef6d7fc..a326a15eda 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/AudioRecorder_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Audio/AudioRecorder1_spec.ts @@ -16,6 +16,7 @@ describe("Audio Recorder functionality tests", () => { 200, ); }); + it("1. Verify properties and sub events are present and js convertible", () => { // assert properties are present propPane.Search("general"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button2_spec.ts index 4c87589e04..25c6ca913c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button2_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button2_spec.ts @@ -125,6 +125,7 @@ describe("Button widget testcases", () => { agHelper.ValidateToastMessage("@example"); // assert after deploy deployMode.DeployApp(); + agHelper.Sleep(); agHelper.ClickButton("Submit"); agHelper.ValidateToastMessage("@example"); deployMode.NavigateBacktoEditor(); @@ -148,14 +149,11 @@ describe("Button widget testcases", () => { propPane._actionSelectorFieldByLabel("Message"), "{{Input1.text}}", ); - propPane.TogglePropertyState("Reset form on success", "On"); deployMode.DeployApp(); + agHelper.Sleep(); // set the email - agHelper.TypeText(clocators.inputField, Cypress.env("USERNAME")); - agHelper.ClickButton("Submit"); - // assert the email set - agHelper.ValidateToastMessage(Cypress.env("USERNAME")); agHelper.ClickButton("Submit"); + agHelper.WaitUntilEleAppear(locators._toastMsg); // on submit form should be reset and default value should ahve populated agHelper.ValidateToastMessage("@example"); deployMode.NavigateBacktoEditor(); @@ -163,12 +161,15 @@ describe("Button widget testcases", () => { entityExplorer.SelectEntityByName("Button1"); propPane.TogglePropertyState("Reset form on success", "Off"); deployMode.DeployApp(); + agHelper.Sleep(); // set the email - agHelper.TypeText(clocators.inputField, Cypress.env("USERNAME")); + agHelper.ClearNType(clocators.inputField, Cypress.env("USERNAME")); agHelper.ClickButton("Submit"); + agHelper.WaitUntilEleAppear(locators._toastMsg); // assert the email on submit agHelper.ValidateToastMessage(Cypress.env("USERNAME")); agHelper.ClickButton("Submit"); + agHelper.WaitUntilEleAppear(locators._toastMsg); // default is set to a different value, so after submit it should not reset to default value, // hene assert the same email which was set agHelper.ValidateToastMessage(Cypress.env("USERNAME")); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup2_spec.ts new file mode 100644 index 0000000000..4244b9aa17 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup2_spec.ts @@ -0,0 +1,166 @@ +import { + agHelper, + deployMode, + draggableWidgets, + entityExplorer, + propPane, + table, + locators, +} from "../../../../../support/Objects/ObjectsCore"; + +import { buttongroupwidgetlocators } from "../../../../../locators/WidgetLocators"; + +describe("Button Group Widget Test", function () { + before("Login to the app and navigate to the workspace", function () { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON_GROUP); + }); + + it("1. Add, Delete more buttons to the group and verify", function () { + agHelper.GetNClick(buttongroupwidgetlocators.newButton); + agHelper.TypeText("//*[ @value='Group Button 1']", " New Button"); + agHelper.AssertContains("Group Button 1 New Button"); + deployMode.DeployApp(); + agHelper + .GetElement(buttongroupwidgetlocators.buttongroup) + .children() + .should("have.length", 4); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + agHelper.GetNClick(table._deleteColumn, 3); + deployMode.DeployApp(); + agHelper + .GetElement(buttongroupwidgetlocators.buttongroup) + .children() + .should("have.length", 3); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + }); + + it("2. Add, Delete menu item to a button group and verify", function () { + // Setting menu values in button More + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 2); + agHelper.GetNClick(buttongroupwidgetlocators.menu); + agHelper.GetNClick(propPane._tableEditColumnButton, 0); + propPane.UpdatePropertyFieldValue("Text", "Option1"); + agHelper.GetNClick(propPane._goBackToProperty); + agHelper.GetNClick(propPane._tableEditColumnButton, 1); + propPane.UpdatePropertyFieldValue("Text", "Option2"); + agHelper.GetNClick(propPane._goBackToProperty); + agHelper.GetNClick(propPane._tableEditColumnButton, 2); + propPane.UpdatePropertyFieldValue("Text", "Option3"); + agHelper.GetNClick(propPane._goBackToProperty); + //deploy and assert all menu values are present + deployMode.DeployApp(); + agHelper.ClickButton("More"); + agHelper.AssertElementExist( + buttongroupwidgetlocators.buttonMenuOptions("Option1"), + ); + agHelper.AssertElementExist( + buttongroupwidgetlocators.buttonMenuOptions("Option2"), + ); + agHelper.AssertElementExist( + buttongroupwidgetlocators.buttonMenuOptions("Option3"), + ); + // delete a menu option and asserts its not available + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 2); + agHelper.GetNClick(buttongroupwidgetlocators.menu); + agHelper.GetNClick(table._deleteColumn, 2); + deployMode.DeployApp(); + agHelper.ClickButton("More"); + agHelper.AssertElementExist( + buttongroupwidgetlocators.buttonMenuOptions("Option1"), + ); + agHelper.AssertElementExist( + buttongroupwidgetlocators.buttonMenuOptions("Option2"), + ); + agHelper.AssertElementAbsence( + buttongroupwidgetlocators.buttonMenuOptions("Option3"), + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + }); + + it("3. Assert button group options - single and menu visibility ", function () { + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(buttongroupwidgetlocators.buttongroup); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + propPane.TogglePropertyState("Visible", "On"); + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 1); + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._buttonByText("Add")); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 1); + propPane.TogglePropertyState("Visible", "On"); + agHelper.GetNClick(propPane._goBackToProperty); + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 2); + // Setting menu values in button More + agHelper.GetNClick(buttongroupwidgetlocators.menu); + agHelper.GetNClick(buttongroupwidgetlocators.menuSettingInPropPane, 0); + propPane.UpdatePropertyFieldValue("Text", "Option 1"); + agHelper.GetNClick(propPane._goBackToProperty); + agHelper.GetNClick(buttongroupwidgetlocators.menuSettingInPropPane, 1); + propPane.UpdatePropertyFieldValue("Text", "Option 2"); + // goto more + agHelper.GetNClick(propPane._goBackToProperty); + //goto the button group + agHelper.GetNClick(propPane._goBackToProperty); + // goto to 1st menu option in more and set it to visible false + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 2); + agHelper.GetNClick(buttongroupwidgetlocators.menu); + agHelper.GetNClick(buttongroupwidgetlocators.menuSettingInPropPane, 0); + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); + agHelper.ClickButton("More"); + // assert option 1 is not visible as its visibility set to false + agHelper.AssertElementAbsence( + buttongroupwidgetlocators.buttonMenuOptions("Option 1"), + ); + agHelper.AssertElementExist( + buttongroupwidgetlocators.buttonMenuOptions("Option 2"), + ); + deployMode.NavigateBacktoEditor(); + }); + + it("4. Assert button group options - single and menu disability ", function () { + entityExplorer.SelectEntityByName("ButtonGroup1"); + deployMode.DeployApp(); + agHelper.AssertElementExist(buttongroupwidgetlocators.buttongroup); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + propPane.TogglePropertyState("Disabled", "On"); + deployMode.DeployApp(); + agHelper.AssertElementEnabledDisabled(buttongroupwidgetlocators.button); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("ButtonGroup1"); + propPane.TogglePropertyState("Disabled", "Off"); + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 2); + // // Setting menu values in button More + agHelper.GetNClick(buttongroupwidgetlocators.menu); + agHelper.GetNClick(buttongroupwidgetlocators.menuSettingInPropPane, 0); + propPane.TogglePropertyState("Disabled", "On"); + propPane.TogglePropertyState("Visible", "On", "updateLayout", false); + agHelper.GetNClick(propPane._goBackToProperty); + deployMode.DeployApp(); + agHelper.ClickButton("More"); + agHelper.AssertElementClassContainsDisabled("//*[text()='Option 1']/.."); + deployMode.NavigateBacktoEditor(); + }); + + it("5. Assert On click button group ", function () { + entityExplorer.DragNDropWidget(draggableWidgets.MODAL, 250, 250); + agHelper.ClickButton("Close"); + entityExplorer.SelectEntityByName("ButtonGroup1"); + agHelper.GetNClick(buttongroupwidgetlocators.buttonSettingInPropPane, 0); + propPane.EnterJSContext("onClick", "{{showModal('Modal1')}}"); + deployMode.DeployApp(); + agHelper.ClickButton("Favorite"); + agHelper.AssertElementExist(locators._modal); + agHelper.ClickButton("Close"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_MenuButton_Width_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_MenuButton_Width_spec.js index 34cbbd371b..4b06b075b9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_MenuButton_Width_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_MenuButton_Width_spec.js @@ -8,8 +8,6 @@ describe("In a button group widget, menu button width", function () { it("1. If target width is smaller than min-width, The menu button popover width should be set to minimum width", () => { cy.get(commonlocators.layoutControls).eq(3).click(); - - const minWidth = 12 * 12.3125; const widgetId = "yxjq5sck7d"; // Get the default menu button cy.get(`.appsmith_widget_${widgetId} div.t--buttongroup-widget`) @@ -18,16 +16,21 @@ describe("In a button group widget, menu button width", function () { .as("target"); // Open popover cy.get("@target").click(); - // Get the target width - agHelper.GetWidth("@target"); - cy.get("@eleWidth").then((targetWidth) => { - expect(targetWidth).to.be.lessThan(minWidth); - // Check if popover width is set to its target width - cy.get(`.bp3-popover2.button-group-${widgetId}`).should( - "have.css", - "width", - `${minWidth}px`, - ); + + agHelper.GetWidth(commonlocators.canvas); + cy.get("@eleWidth").then((mainCanvasWidth) => { + const minWidth = (12 / 64) * mainCanvasWidth; + // Get the target width + agHelper.GetWidth("@target"); + cy.get("@eleWidth").then((targetWidth) => { + expect(targetWidth).to.be.lessThan(minWidth); + // Check if popover width is set to its target width + cy.get(`.bp3-popover2.button-group-${widgetId}`).should( + "have.css", + "width", + `${minWidth}px`, + ); + }); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_spec.js index 4bf91b856a..01651e4ff8 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/ButtonGroup_spec.js @@ -1,21 +1,28 @@ const explorer = require("../../../../../locators/explorerlocators.json"); const { modifierKey } = require("../../../../../support/Constants"); +import { draggableWidgets } from "../../../../../support/Objects/ObjectsCore"; +import { + entityExplorer, + agHelper, + assertHelper, +} from "../../../../../support/Objects/ObjectsCore"; + +import { buttongroupwidgetlocators } from "../../../../../locators/WidgetLocators"; + +import { PropertyPane } from "../../../../../support/Pages/PropertyPane"; + const firstButton = ".t--buttongroup-widget > div > button > div"; const menuButton = ".t--buttongroup-widget .bp3-popover2-target > div > button > div"; describe("Button Group Widget Functionality", function () { before(() => { - // no dsl required - }); - - it("Add new Button Group", () => { - cy.wait(1000); - cy.get(explorer.addWidget).click(); - cy.dragAndDropToCanvas("buttongroupwidget", { x: 300, y: 300 }); - cy.get(".t--buttongroup-widget").should("exist"); - cy.get(".t--buttongroup-widget").children().should("have.length", 3); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON_GROUP); + agHelper + .GetElement(buttongroupwidgetlocators.buttongroup) + .children() + .should("have.length", 3); }); it("ButtonGroup Widget Functionality on undo after delete", function () { @@ -25,19 +32,25 @@ describe("Button Group Widget Functionality", function () { }); // Check if the Button got deleted - cy.get(".t--buttongroup-widget").children().should("have.length", 2); + agHelper + .GetElement(buttongroupwidgetlocators.buttongroup) + .children() + .should("have.length", 2); // Check the first button - cy.get(firstButton).contains("Add"); + agHelper.GetNAssertElementText(firstButton, "Add"); // Undo cy.get("body").type(`{${modifierKey}+z}`); // Check if the button is back - cy.get(".t--buttongroup-widget").children().should("have.length", 3); + agHelper + .GetElement(buttongroupwidgetlocators.buttongroup) + .children() + .should("have.length", 3); // Check the first button - cy.get(firstButton).contains("Favorite"); + agHelper.GetNAssertElementText(firstButton, "Favorite"); // Navigate to the first button property pane cy.get(".t--property-control-buttons .t--edit-column-btn").eq(0).click({ diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Image_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Image_Spec.ts index ba35f91370..3fb6399d29 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Image_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Image_Spec.ts @@ -75,13 +75,13 @@ describe("Camera widget - Image test", () => { agHelper.AssertExistingToggleState("Mirrored", "true"); propPane.EnterJSContext("Mirrored", "{{(55>45)?false:true}}", true, true); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) .matchImageSnapshot("cameraImageMirroredScreen", { failureThreshold: 0.15, failureThresholdType: "percent", customDiffConfig: { threshold: 0.15 }, - }); */ + }); deployMode.NavigateBacktoEditor(); entityExplorer.SelectEntityByName("Camera1"); propPane.EnterJSContext("Mirrored", "", false); @@ -114,9 +114,9 @@ describe("Camera widget - Image test", () => { //Validate camera screen & icons agHelper.AssertElementVisibility(widgetLocators.cameraImageVideoOnOffBtn); agHelper.AssertElementVisibility(widgetLocators.cameraImageVideoDropdown); - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) - .matchImageSnapshot("cameraImageScreen"); */ + .matchImageSnapshot("cameraImageScreen"); //Capture image agHelper.GetNClick(widgetLocators.cameraCaptureBtn); @@ -124,18 +124,18 @@ describe("Camera widget - Image test", () => { agHelper.AssertElementVisibility(widgetLocators.cameraImageDiscardBtn); //Validate image in preview screen - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) - .matchImageSnapshot("cameraImagePreviewScreen"); */ + .matchImageSnapshot("cameraImagePreviewScreen"); //Save image agHelper.GetNClick(widgetLocators.cameraSaveBtn); agHelper.AssertElementVisibility(widgetLocators.cameraRefreshBtn); //Validate image in refresh screen - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) - .matchImageSnapshot("cameraImageSavedScreen"); */ + .matchImageSnapshot("cameraImageSavedScreen"); //Refresh image agHelper.GetNClick(widgetLocators.cameraRefreshBtn); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Video_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Video_Spec.ts index 2045d9d601..977ff16262 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Video_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Camera/Video_Spec.ts @@ -58,9 +58,9 @@ describe("Camera widget - Video test", () => { agHelper.AssertExistingToggleState("Mirrored", "true"); propPane.EnterJSContext("Mirrored", "{{(55>45)?false:true}}", true, true); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) - .matchImageSnapshot("cameraVideoMirroredScreen"); */ + .matchImageSnapshot("cameraVideoMirroredScreen"); deployMode.NavigateBacktoEditor(); entityExplorer.SelectEntityByName("Camera1"); propPane.EnterJSContext("Mirrored", "", false); @@ -95,9 +95,9 @@ describe("Camera widget - Video test", () => { agHelper.AssertElementVisibility(widgetLocators.cameraMicrophoneDropdown); agHelper.AssertElementVisibility(widgetLocators.cameraVideoOnOffBtn); agHelper.AssertElementVisibility(widgetLocators.cameraVideoDropdown); - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) - .matchImageSnapshot("cameraVideoScreen"); */ + .matchImageSnapshot("cameraVideoScreen"); //Start video recording agHelper.GetNClick(widgetLocators.cameraCaptureBtn); @@ -110,18 +110,18 @@ describe("Camera widget - Video test", () => { agHelper.AssertElementVisibility(widgetLocators.cameraVideoPlayBtn); //Validate video in preview screen - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) - .matchImageSnapshot("cameraVideoPreviewScreen"); */ + .matchImageSnapshot("cameraVideoPreviewScreen"); //Save video agHelper.GetNClick(widgetLocators.cameraSaveBtn); //Validate video in refresh screen agHelper.AssertElementVisibility(widgetLocators.cameraRefreshBtn); - /* agHelper + agHelper .GetElement(locators._widgetInDeployed(draggableWidgets.CAMERA)) - .matchImageSnapshot("cameraVideoSavedScreen"); */ + .matchImageSnapshot("cameraVideoSavedScreen"); //Refresh video agHelper.GetNClick(widgetLocators.cameraRefreshBtn); @@ -154,108 +154,109 @@ describe("Camera widget - Video test", () => { table.ValidateDownloadNVerify("video.mp4"); }); + //Tests to Validate camera to video widget binding //Skipping below tests due to issue - https://github.com/appsmithorg/appsmith/issues/26166 - it.skip("7. Video Recording test - Disabled Camera but Enabled Microphone", () => { - deployMode.NavigateBacktoEditor(); - entityExplorer.SelectEntityByName("Camera1"); - agHelper.GetNClick(propPane._mode("Video"), 1); - entityExplorer.DragNDropWidget(draggableWidgets.VIDEO); - propPane.TypeTextIntoField("URL", "{{Camera1.videoBlobURL}}"); + // it("7. Video Recording test - Disabled Camera but Enabled Microphone", () => { + // deployMode.NavigateBacktoEditor(); + // entityExplorer.SelectEntityByName("Camera1"); + // agHelper.GetNClick(propPane._mode("Video"), 1); + // entityExplorer.DragNDropWidget(draggableWidgets.VIDEO); + // propPane.TypeTextIntoField("URL", "{{Camera1.videoBlobURL}}"); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); - agHelper.GetNClick(widgetLocators.cameraVideoOnOffBtn); - agHelper.GetNClick(widgetLocators.cameraCaptureBtn); - agHelper.Sleep(3000); - agHelper.GetNClick(widgetLocators.cameraStopRecordingBtn); - agHelper.GetNClick(widgetLocators.cameraSaveBtn); - agHelper.GetNClick(draggableWidgets.VIDEO); - agHelper.Sleep(5000); - agHelper - .GetElement(widgetLocators.cameraVideo) - .eq(1) - .should(($el) => { - const attrValue = $el[0].webkitAudioDecodedByteCount; + // deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); + // agHelper.GetNClick(widgetLocators.cameraVideoOnOffBtn); + // agHelper.GetNClick(widgetLocators.cameraCaptureBtn); + // agHelper.Sleep(3000); + // agHelper.GetNClick(widgetLocators.cameraStopRecordingBtn); + // agHelper.GetNClick(widgetLocators.cameraSaveBtn); + // agHelper.GetNClick(draggableWidgets.VIDEO); + // agHelper.Sleep(5000); + // agHelper + // .GetElement(widgetLocators.cameraVideo) + // .eq(1) + // .should(($el) => { + // const attrValue = $el[0].webkitAudioDecodedByteCount; - //Threshold greater than 30000 shows that the audio is playing - expect(attrValue).be.greaterThan(30000); - }); - agHelper - .GetElement(widgetLocators.cameraVideo) - .eq(1) - .should(($el) => { - const attrValue = $el[0].webkitVideoDecodedByteCount; + // //Threshold greater than 30000 shows that the audio is playing + // expect(attrValue).be.greaterThan(30000); + // }); + // agHelper + // .GetElement(widgetLocators.cameraVideo) + // .eq(1) + // .should(($el) => { + // const attrValue = $el[0].webkitVideoDecodedByteCount; - //Threshold less than 10000 shows that the video is not playing - expect(attrValue).be.lessThan(10000); - }); - }); + // //Threshold less than 10000 shows that the video is not playing + // expect(attrValue).be.lessThan(10000); + // }); + // }); - it.skip("8. Video Recording test - Enabled Camera but Disabled Microphone", () => { - entityExplorer.SelectEntityByName("Camera1"); - agHelper.GetNClick(propPane._mode("Video"), 1); - entityExplorer.DragNDropWidget(draggableWidgets.VIDEO); - propPane.TypeTextIntoField("URL", "{{Camera1.videoBlobURL}}"); + // it("8. Video Recording test - Enabled Camera but Disabled Microphone", () => { + // entityExplorer.SelectEntityByName("Camera1"); + // agHelper.GetNClick(propPane._mode("Video"), 1); + // entityExplorer.DragNDropWidget(draggableWidgets.VIDEO); + // propPane.TypeTextIntoField("URL", "{{Camera1.videoBlobURL}}"); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); - agHelper.GetNClick(widgetLocators.cameraVideoOnOffBtn); - agHelper.GetNClick(widgetLocators.cameraMicrophoneBtn); - agHelper.GetNClick(widgetLocators.cameraCaptureBtn); - agHelper.Sleep(3000); - agHelper.GetNClick(widgetLocators.cameraStopRecordingBtn); - agHelper.GetNClick(widgetLocators.cameraSaveBtn); - agHelper.GetNClick(draggableWidgets.VIDEO); - agHelper.Sleep(5000); - agHelper - .GetElement(widgetLocators.cameraVideo) - .eq(1) - .should(($el) => { - const attrValue = $el[0].webkitAudioDecodedByteCount; + // deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); + // agHelper.GetNClick(widgetLocators.cameraVideoOnOffBtn); + // agHelper.GetNClick(widgetLocators.cameraMicrophoneBtn); + // agHelper.GetNClick(widgetLocators.cameraCaptureBtn); + // agHelper.Sleep(3000); + // agHelper.GetNClick(widgetLocators.cameraStopRecordingBtn); + // agHelper.GetNClick(widgetLocators.cameraSaveBtn); + // agHelper.GetNClick(draggableWidgets.VIDEO); + // agHelper.Sleep(5000); + // agHelper + // .GetElement(widgetLocators.cameraVideo) + // .eq(1) + // .should(($el) => { + // const attrValue = $el[0].webkitAudioDecodedByteCount; - //Threshold less than 1000 shows that the audio is not playing - expect(attrValue).be.lessThan(1000); - }); - agHelper - .GetElement(widgetLocators.cameraVideo) - .eq(1) - .should(($el) => { - const attrValue = $el[0].webkitVideoDecodedByteCount; + // //Threshold less than 1000 shows that the audio is not playing + // expect(attrValue).be.lessThan(1000); + // }); + // agHelper + // .GetElement(widgetLocators.cameraVideo) + // .eq(1) + // .should(($el) => { + // const attrValue = $el[0].webkitVideoDecodedByteCount; - //Threshold greater than 30000 shows that the video is playing - expect(attrValue).be.greaterThan(30000); - }); - }); + // //Threshold greater than 30000 shows that the video is playing + // expect(attrValue).be.greaterThan(30000); + // }); + // }); - it.skip("9. Video Recording test - Enabled Camera but Enabled Microphone", () => { - entityExplorer.SelectEntityByName("Camera1"); - agHelper.GetNClick(propPane._mode("Video"), 1); - entityExplorer.DragNDropWidget(draggableWidgets.VIDEO); - propPane.TypeTextIntoField("URL", "{{Camera1.videoBlobURL}}"); + // it("9. Video Recording test - Enabled Camera but Enabled Microphone", () => { + // entityExplorer.SelectEntityByName("Camera1"); + // agHelper.GetNClick(propPane._mode("Video"), 1); + // entityExplorer.DragNDropWidget(draggableWidgets.VIDEO); + // propPane.TypeTextIntoField("URL", "{{Camera1.videoBlobURL}}"); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); - agHelper.GetNClick(widgetLocators.cameraMicrophoneBtn); - agHelper.GetNClick(widgetLocators.cameraCaptureBtn); - agHelper.Sleep(3000); - agHelper.GetNClick(widgetLocators.cameraStopRecordingBtn); - agHelper.GetNClick(widgetLocators.cameraSaveBtn); - agHelper.GetNClick(draggableWidgets.VIDEO); - agHelper.Sleep(5000); - agHelper - .GetElement(widgetLocators.cameraVideo) - .eq(1) - .should(($el) => { - const attrValue = $el[0].webkitAudioDecodedByteCount; + // deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CAMERA)); + // agHelper.GetNClick(widgetLocators.cameraMicrophoneBtn); + // agHelper.GetNClick(widgetLocators.cameraCaptureBtn); + // agHelper.Sleep(3000); + // agHelper.GetNClick(widgetLocators.cameraStopRecordingBtn); + // agHelper.GetNClick(widgetLocators.cameraSaveBtn); + // agHelper.GetNClick(draggableWidgets.VIDEO); + // agHelper.Sleep(5000); + // agHelper + // .GetElement(widgetLocators.cameraVideo) + // .eq(1) + // .should(($el) => { + // const attrValue = $el[0].webkitAudioDecodedByteCount; - //Threshold less than 30000 shows that the audio is playing - expect(attrValue).be.greaterThan(30000); - }); - agHelper - .GetElement(widgetLocators.cameraVideo) - .eq(1) - .should(($el) => { - const attrValue = $el[0].webkitVideoDecodedByteCount; + // //Threshold greater than 30000 shows that the audio is playing + // expect(attrValue).be.greaterThan(30000); + // }); + // agHelper + // .GetElement(widgetLocators.cameraVideo) + // .eq(1) + // .should(($el) => { + // const attrValue = $el[0].webkitVideoDecodedByteCount; - //Threshold less than 30000 shows that the video is playing - expect(attrValue).be.greaterThan(30000); - }); - }); + // //Threshold greater than 30000 shows that the video is playing + // expect(attrValue).be.greaterThan(30000); + // }); + // }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts index f65a58b395..dcd3eb1a2b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts @@ -5,6 +5,7 @@ import { deployMode, locators, entityExplorer, + draggableWidgets, } from "../../../../../support/Objects/ObjectsCore"; const widgetLocators = require("../../../../../locators/Widgets.json"); @@ -12,7 +13,7 @@ const widgetLocators = require("../../../../../locators/Widgets.json"); let dataSet: any, dsl: any; describe("Input widget test with default value from chart datapoint", () => { - //beforeEach - becasuse to enable re-attempt passing! + //beforeEach - to enable re-attempt passing! beforeEach(() => { agHelper.AddDsl("ChartDsl"); cy.fixture("ChartDsl").then((val: any) => { @@ -23,11 +24,6 @@ describe("Input widget test with default value from chart datapoint", () => { }); }); - afterEach(() => { - //this is to enable re-attempt passing! - deployMode.NavigateBacktoEditor(); - }); - it("1. Chart widget - Input widget test with default value from another Input widget", () => { entityExplorer.SelectEntityByName("Input1", "Widgets"); propPane.UpdatePropertyFieldValue( @@ -44,7 +40,7 @@ describe("Input widget test with default value from chart datapoint", () => { "Default value", dataSet.bindingSeriesTitle + "}}", ); - deployMode.DeployApp(); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CHART)); agHelper.Sleep(1500); //waiting for chart to load! agHelper.GetNClickByContains(widgetLocators.chartDataPoint, "36000"); cy.get(locators._widgetInputSelector("inputwidgetv2")) @@ -58,48 +54,26 @@ describe("Input widget test with default value from chart datapoint", () => { cy.get(locators._widgetInputSelector("inputwidgetv2")) .last() .should("have.value", dsl.dsl.children[0].chartData[0].seriesName); + + deployMode.NavigateBacktoEditor(); }); it("2. onDataPointClick should work and respond with x, y, seriesTitle, and rawEventData (in case of custom fusion chart).", () => { - assertHelper.AssertNetworkStatus("@updateLayout"); - entityExplorer.SelectEntityByName("Chart1"); - propPane.TogglePropertyState("Show Labels", "On"); - propPane.SelectPlatformFunction("onDataPointClick", "Show alert"); - agHelper.EnterActionValue("Message", dataSet.bindingDataPoint); - - deployMode.DeployApp(); - agHelper.Sleep(1500); //waiting for chart to load! - - agHelper.GetNClickByContains(widgetLocators.chartDataPoint, "36000"); - cy.get(locators._toastMsg).should( - "have.text", - `{"x":"Sun","y":36000,"seriesTitle":"Sales"}`, - ); - deployMode.NavigateBacktoEditor(); - agHelper.AddDsl("chartCustomSankeyDataDsl"); - cy.fixture("chartCustomSankeyDataDsl").then((val: any) => { - dsl = val; - }); - cy.fixture("testdata").then(function (data: any) { - dataSet = data; - }); - assertHelper.AssertNetworkStatus("@updateLayout"); entityExplorer.SelectEntityByName("Chart1"); + agHelper.Sleep(1500); //waiting for chart to load! propPane.SelectPlatformFunction("onDataPointClick", "Show alert"); agHelper.EnterActionValue("Message", dataSet.bindingDataPoint); - deployMode.DeployApp(); - + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.CHART)); agHelper.Sleep(1500); //waiting for chart to load! agHelper.GetNClickByContains( widgetLocators.chartDataPoint, "European Union", ); - cy.get(locators._toastMsg).should( - "have.text", - `{"x":-1,"y":-1,"seriesTitle":"","rawEventData":{"color":"#FFC533","alpha":100,"labelFill":"#666","labelAlpha":100,"value":4747591,"label":"European Union","sourceLinks":["France","United States","United Kingdom","Switzerland","Austria","Sweden"],"targetLinks":["Netherlands","Germany","Belgium","China","Italy","Russia","Spain"]}}`, + agHelper.ValidateToastMessage( + '{"rawEventData":{"color":"#FFC533","alpha":100,"labelFill":"#666","labelAlpha":100,"value":4747591,"label":"European Union","sourceLinks":["France","United States","United Kingdom","Switzerland","Austria","Sweden"],"targetLinks":["Netherlands","Germany","Belgium","China","Italy","Russia","Spain"]}}', ); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Chart_widget_spec_1.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Chart_widget_spec_1.ts new file mode 100644 index 0000000000..7114e7c76f --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Chart_widget_spec_1.ts @@ -0,0 +1,85 @@ +import { + agHelper, + entityExplorer, + deployMode, + draggableWidgets, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("", () => { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.CHART); + }); + + afterEach(() => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + }); + + it("1. Test pie chart", () => { + propPane.SelectPropertiesDropDown("Chart Type", "Pie chart"); + agHelper.AssertAutoSave(); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/piechartsnapshot"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + propPane.TogglePropertyState("Show Labels", "On"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/piechartsnapshotwithlabels"); + }); + + it("2. Test line chart", () => { + propPane.TogglePropertyState("Show Labels", "Off"); + propPane.SelectPropertiesDropDown("Chart Type", "Line chart"); + agHelper.AssertAutoSave(); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/linechartsnapshot"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + propPane.TogglePropertyState("Show Labels", "On"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/linechartsnapshotwithlabels"); + }); + + it("3. Test column chart", () => { + propPane.TogglePropertyState("Show Labels", "Off"); + propPane.SelectPropertiesDropDown("Chart Type", "Column chart"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/columnchartsnapshot"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + propPane.TogglePropertyState("Show Labels", "On"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/columnchartsnapshotwithlabels"); + }); + + it("4. Test area chart", () => { + propPane.TogglePropertyState("Show Labels", "Off"); + propPane.SelectPropertiesDropDown("Chart Type", "Area chart"); + agHelper.AssertAutoSave(); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/areachartsnapshot"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + propPane.TogglePropertyState("Show Labels", "On"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/areachartsnapshotwithlabels"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Chart_widget_spec_2.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Chart_widget_spec_2.ts new file mode 100644 index 0000000000..c447a74315 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Chart_widget_spec_2.ts @@ -0,0 +1,94 @@ +import { + agHelper, + entityExplorer, + deployMode, + draggableWidgets, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("", () => { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.CHART); + }); + + it("1. Test Series tile chart", () => { + propPane.SelectPropertiesDropDown("Chart Type", "Pie chart"); + propPane.UpdatePropertyFieldValue( + "Title", + "Data of anime at 2020 @ December", + ); + agHelper.AssertAutoSave(); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/piechartsnapshotwithtitle"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + }); + + it("2. Test Adaptive axis", () => { + propPane.SelectPropertiesDropDown("Chart Type", "Column chart"); + agHelper.AssertAutoSave(); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/columnchartsnapshotwithoutadaptiveaxis"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + propPane.TogglePropertyState("Adaptive axis", "On"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/columnchartsnapshotwithadaptiveaxis"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + }); + + it("3. Test x axis label orientation chart", () => { + propPane.SelectPropertiesDropDown("Chart Type", "Line chart"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot("chartwidget/linechartWithAutoXAxisLabelOrientation"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + propPane.SelectPropertiesDropDown("x-axis label orientation", "Slant"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot( + "chartwidget/linechartWithSlantXAxisLabelOrientation", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + propPane.SelectPropertiesDropDown("x-axis label orientation", "Rotate"); + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.CHART)) + .matchImageSnapshot( + "chartwidget/linechartWithRotateXAxisLabelOrientation", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Chart1"); + }); + + it("4. Test x axis label orientation absence in Pie, Bar, Custom Fusion Charts", () => { + propPane.SelectPropertiesDropDown("Chart Type", "Pie chart"); + agHelper.AssertElementAbsence( + propPane._selectPropDropdown("x-axis label orientation"), + ); + propPane.SelectPropertiesDropDown("Chart Type", "Bar chart"); + agHelper.AssertElementAbsence( + propPane._selectPropDropdown("x-axis label orientation"), + ); + propPane.SelectPropertiesDropDown("Chart Type", "Custom Fusion Charts"); + agHelper.AssertElementAbsence( + propPane._selectPropDropdown("x-axis label orientation"), + ); + propPane.SelectPropertiesDropDown("Chart Type", "Column chart"); + agHelper.AssertElementExist( + propPane._selectPropDropdown("x-axis label orientation"), + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom3DChartSpec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom3DChartSpec.ts new file mode 100644 index 0000000000..ab44a2c03b --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom3DChartSpec.ts @@ -0,0 +1,20 @@ +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; +import * as _ from "../../../../../support/Objects/ObjectsCore"; +const publicWidgetsPage = require("../../../../../locators/publishWidgetspage.json"); + +describe("3D Custom EChart feature", function () { + it("1. 3D EChart Custom Chart Widget Functionality", function () { + featureFlagIntercept({ + release_custom_echarts_enabled: true, + }); + _.agHelper.RefreshPage(); + _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.CHART); + _.propPane.SelectPropertiesDropDown("Chart type", "Custom EChart"); + _.propPane.UpdatePropertyFieldValue( + "Custom ECharts Configuration", + `{{${JSON.stringify(this.dataSet.Custom3DEChartConfig)}}}`, + ); + _.deployMode.DeployApp(); + cy.get(publicWidgetsPage.chartWidget).matchImageSnapshot("3DCustomECharts"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_Data_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_Data_spec.js index 7ae27b0709..8cfaa653a6 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_Data_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_Data_spec.js @@ -1,4 +1,5 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; describe("Chart Widget Functionality around custom chart data", function () { before(() => { @@ -7,8 +8,11 @@ describe("Chart Widget Functionality around custom chart data", function () { it("1. change chart type to custom chart", function () { const value1 = 40; + featureFlagIntercept({ + deprecate_custom_fusioncharts_enabled: true, + }); cy.openPropertyPane("chartwidget"); - cy.UpdateChartType("Custom chart"); + cy.UpdateChartType("Custom Fusion Charts (deprecated)"); //change chart value via input widget and validate enterAndTest("inputwidgetv2", value1, value1); cy.wait(400); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_spec.js index 8a8f8d8fa3..974b62b294 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/Custom_Chart_spec.js @@ -1,6 +1,7 @@ const viewWidgetsPage = require("../../../../../locators/ViewWidgets.json"); const widgetsPage = require("../../../../../locators/Widgets.json"); import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; import * as _ from "../../../../../support/Objects/ObjectsCore"; @@ -25,6 +26,13 @@ describe("Chart Widget Functionality around custom chart feature", function () { viewWidgetsPage.chartWidget, widgetsPage.widgetNameSpan, ); + + //Entering the Chart data + cy.testJsontext( + "chart-series-data-control", + JSON.stringify(this.dataSet.chartInput), + ); + //changing the Chart Title /** * @param{Text} Random Input Value @@ -34,11 +42,6 @@ describe("Chart Widget Functionality around custom chart feature", function () { .contains("App Sign Up") .should("have.text", "App Sign Up"); - //Entering the Chart data - cy.testJsontext( - "chart-series-data-control", - JSON.stringify(this.dataSet.chartInput), - ); cy.get(".t--propertypane").click("right"); // Asserting Chart Height @@ -68,13 +71,20 @@ describe("Chart Widget Functionality around custom chart feature", function () { it("2. Custom Chart Widget Functionality", function () { //changing the Chart type //cy.get(widgetsPage.toggleChartType).click({ force: true }); - cy.UpdateChartType("Custom chart"); + featureFlagIntercept({ + deprecate_custom_fusioncharts_enabled: true, + }); + cy.UpdateChartType("Custom Fusion Charts (deprecated)"); cy.testJsontext( "customfusionchart", `{{${JSON.stringify(this.dataSet.ChartCustomConfig)}}}`, ); + _.agHelper.AssertContains( + "Custom Fusion Charts will stop being supported on March 1st 2024. Change the chart type to E-charts Custom to switch.", + ); + //Verifying X-axis labels cy.get(viewWidgetsPage.chartWidget).should("have.css", "opacity", "1"); const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBoxGroupTest.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBoxGroupTest.ts new file mode 100644 index 0000000000..4f83b305aa --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBoxGroupTest.ts @@ -0,0 +1,458 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, + dataSources, + entityItems, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Checkbox Tests", function () { + before(() => { + entityExplorer.DragDropWidgetNVerify("checkboxgroupwidget", 550, 100); + }); + + it("1. Verify property visibility", function () { + const defaultProperties = ["options", "defaultselectedvalues"]; + const labelProperties = ["text", "position"]; + const generalProperties = [ + "tooltip", + "visible", + "disabled", + "inline", + "selectalloptions", + "animateloading", + "height", + ]; + const eventsProperties = ["onselectionchange"]; + const validationsProperties = ["required"]; + const labelStylesProperties = ["fontcolor", "fontsize", "emphasis"]; + const styleGeneralProperties = ["alignment"]; + const styleColorProperties = ["accentcolor"]; + + entityExplorer.SelectEntityByName("CheckboxGroup1", "Widgets"); + defaultProperties.forEach((defaultSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "data", + `${defaultSectionProperty}`, + ), + ); + }); + // Label Section properties + labelProperties.forEach((labelSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "label", + `${labelSectionProperty}`, + ), + ); + }); + // General Section properties + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + // Events Section properties + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("events", `${eventsProperties}`), + ); + // Validation Section properties + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "validations", + `${validationsProperties}`, + ), + ); + // Style Section properties + propPane.MoveToTab("Style"); + // Label Style Section properties + labelStylesProperties.forEach((labelSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "labelstyles", + `${labelSectionProperty}`, + ), + ); + }); + // General Style Section properties + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${styleGeneralProperties}`, + ), + ); + // Color Style Section properties + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("color", `${styleColorProperties}`), + ); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "CheckboxGroup1", + "NewCheckBox", + true, + ); + agHelper.AssertElementVisibility(locators._widgetName("NewCheckBox")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewCheckBox"); + entityExplorer.AssertEntityPresenceInExplorer("NewCheckBoxCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewCheckBoxCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewCheckBox"); + propPane.DeleteWidgetFromPropertyPane("NewCheckBoxCopy"); + }); + + it("3. Verify Data can be added and deleted", () => { + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.MoveToTab("Content"); + agHelper.GetElementLength(propPane._placeholderName).then((len) => { + agHelper.GetNClick(propPane._addOptionProperty); + agHelper.RemoveCharsNType(propPane._placeholderName, -1, "Black", 3); + agHelper.RemoveCharsNType(propPane._placeholderValue, -1, "BLACK", 3); + // Verify option added + agHelper.AssertElementLength(propPane._placeholderName, len + 1); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementLength(propPane._checkbox, len + 1); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementLength(propPane._checkbox, len + 1); + deployMode.NavigateBacktoEditor(); + + // Delete option + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + agHelper.GetNClick(propPane._optionsDeleteButton, 3); + // Verify option deleted + agHelper.AssertElementLength(propPane._placeholderName, len); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementLength(propPane._checkbox, len); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementLength(propPane._checkbox, len); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + }); + }); + + it("4. Verify changing Label text and position", () => { + propPane.UpdatePropertyFieldValue("Text", "New Label"); + agHelper.AssertText(locators._label, "text", "New Label"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Left')`); + agHelper.AssertAttribute(locators._label, "position", "Left"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "position", "Left"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "position", "Left"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Top')`); + agHelper.AssertAttribute(locators._label, "position", "Top"); + }); + + it("5. Verify tooltip", () => { + entityExplorer.DragDropWidgetNVerify("currencyinputwidget", 550, 300); + propPane.UpdatePropertyFieldValue("Default value", "1000"); + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "{{CurrencyInput1.text}}"); + agHelper.HoverElement(locators._checkboxHelpIcon); + agHelper.AssertPopoverTooltip("1,000"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.HoverElement(locators._checkboxHelpIcon); + agHelper.AssertPopoverTooltip("1,000"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.HoverElement(locators._checkboxHelpIcon); + agHelper.AssertPopoverTooltip("1,000"); + deployMode.NavigateBacktoEditor(); + }); + + it("6. Verify onSelectionChange Navigat to", () => { + entityExplorer.AddNewPage(); + entityExplorer.SelectEntityByName("Page1"); + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.SelectPlatformFunction("onSelectionChange", "Navigate to"); + dataSources.ValidateNSelectDropdown("Choose page", "Select page", "Page2"); + agHelper.Sleep(2000); + agHelper.GetNClick(propPane._checkbox, 1, true); + entityExplorer.VerifyIsCurrentPage("Page2"); + entityExplorer.SelectEntityByName("Page1"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNClick(propPane._checkbox, 1, true); + entityExplorer.VerifyIsCurrentPage("Page2"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNClick(propPane._checkbox, 1, true); + agHelper + .GetElement(`${locators._deployedPage}:contains("Page2")`) + .should("have.class", "is-active"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("Page1"); + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + }); + + it("7. Verify Full color picker and font size", () => { + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + // Verify font color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("fontcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("fontcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + // Font size + propPane.SelectPropertiesDropDown("fontsize", "L"); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "L"); + propPane.ToggleJSMode("fontsize", true); + propPane.UpdatePropertyFieldValue("Font size", "1rem"); + propPane.ToggleJSMode("fontsize", false); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "M"); + // Verify Emphasis + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.AssertAttribute(locators._label, "font-style", "BOLD"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + propPane.ToggleJSMode("emphasis", true); + propPane.UpdatePropertyFieldValue("Emphasis", "ITALIC"); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.MoveToTab("Style"); + cy.wait(1000); + // Verify Accent color + propPane.SelectColorFromColorPicker("accentcolor", -15); + agHelper.AssertAttribute( + `${locators._propertyControl}accentcolor ${propPane._roundCursorPointer}`, + "color", + "#dbeafe", + ); + propPane.ToggleJSMode("accentcolor", true); + propPane.UpdatePropertyFieldValue( + "Accent color", + "{{appsmith.theme.colors.primaryColor}}", + ); + propPane.ToggleJSMode("accentcolor", false); + agHelper.AssertAttribute( + `${locators._propertyControl}accentcolor ${propPane._roundCursorPointer}`, + "color", + "#553DE9", + ); + // Verify full color picker for accent color + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 1); + propPane.TogglePropertyState("accentcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 1); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertAttribute( + `${propPane._checkbox} input`, + "borderradius", + "0px", + ); + propPane.ToggleJSMode("borderradius", true); + propPane.UpdatePropertyFieldValue("Border radius", "0.375rem"); + agHelper.AssertAttribute( + `${propPane._checkbox} input`, + "borderradius", + "0.375rem", + ); + }); + + it("8. Verify checkbox properties by updating text widget", () => { + const options = + '[{"label":"Blue","value":"BLUE"},{"label":"Green","value":"GREEN"},{"label":"Red","value":"RED"}]'; + + entityExplorer.DragDropWidgetNVerify("textwidget", 550, 500); + propPane.UpdatePropertyFieldValue("Text", "{{NewCheckBox.isVisible}}"); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + deployMode.NavigateBacktoEditor(); + + // Verify checkbox visible + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.MoveToTab("Content"); + propPane.TogglePropertyState("visible", "Off"); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "false", + ); + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "false", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "false", + ); + + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.MoveToTab("Content"); + propPane.TogglePropertyState("visible", "On"); + // Verify checkbox disabled + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.MoveToTab("Content"); + propPane.UpdatePropertyFieldValue("Text", "{{NewCheckBox.isDisabled}}"); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "false", + ); + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "false", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "false", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.MoveToTab("Content"); + propPane.TogglePropertyState("disabled", "On"); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("NewCheckBox", "Widgets"); + propPane.MoveToTab("Content"); + propPane.TogglePropertyState("disabled", "Off"); + + // Verify selected value[All values selected] + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.MoveToTab("Content"); + propPane.UpdatePropertyFieldValue("Text", "{{NewCheckBox.selectedValues}}"); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Page2", + action: "Delete", + entityType: entityItems.Page, + }); + agHelper.GetNClick(locators._checkboxWidgetLabel, 1); + agHelper.GetNClick(locators._checkboxWidgetLabel, 2); + agHelper.GetNAssertContains(locators._textWidget, '"BLUE"'); + agHelper.GetNAssertContains(locators._textWidget, '"GREEN"'); + agHelper.GetNAssertContains(locators._textWidget, '"RED"'); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNAssertContains(locators._textWidgetContaioner, '"BLUE"'); + agHelper.GetNAssertContains(locators._textWidgetContaioner, '"GREEN"'); + agHelper.GetNAssertContains(locators._textWidgetContaioner, '"RED"'); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNClick(locators._checkboxWidgetLabel, 1); + agHelper.GetNClick(locators._checkboxWidgetLabel, 2); + agHelper.GetNAssertContains(locators._textWidgetContaioner, '"BLUE"'); + agHelper.GetNAssertContains(locators._textWidgetContaioner, '"GREEN"'); + agHelper.GetNAssertContains(locators._textWidgetContaioner, '"RED"'); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.MoveToTab("Content"); + propPane.UpdatePropertyFieldValue("Text", "{{NewCheckBox.isValid}}"); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNAssertContains( + locators._widgetInDeployed("textwidget"), + "true", + ); + deployMode.NavigateBacktoEditor(); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner1_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner1_spec.ts index 9847c98612..c39d2a2c17 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner1_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner1_spec.ts @@ -3,7 +3,6 @@ import publish from "../../../../../locators/publishWidgetspage.json"; import commonlocators from "../../../../../locators/commonlocators.json"; import widgetsPage from "../../../../../locators/Widgets.json"; import * as _ from "../../../../../support/Objects/ObjectsCore"; - const widgetName = "codescannerwidget"; const codeScannerVideoOnPublishPage = `${publish.codescannerwidget} ${commonlocators.codeScannerVideo}`; const codeScannerDisabledSVGIconOnPublishPage = `${publish.codescannerwidget} ${commonlocators.codeScannerDisabledSVGIcon}`; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner2_spec.ts index 9b7387db58..01a1c54ffa 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner2_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CodeScanner/CodeScanner2_spec.ts @@ -51,7 +51,7 @@ describe("Code scanner widget tests", () => { propPane.TogglePropertyState("Disabled", "Off"); //Animate loading property - JS convertible - agHelper.AssertExistingToggleState("animateloading", "true"); + agHelper.AssertExistingToggleState("Animate loading", "true"); propPane.EnterJSContext( "Animate loading", "{{(45>55)?false:true}}", @@ -63,8 +63,8 @@ describe("Code scanner widget tests", () => { "{{(45>55)?false:true}}", ); propPane.EnterJSContext("Animate loading", "", false); - propPane.ToggleJSMode("animateloading", false); - propPane.TogglePropertyState("animateloading", "On"); + propPane.ToggleJSMode("Animate loading", false); + propPane.TogglePropertyState("Animate loading", "On"); }); it( @@ -135,7 +135,7 @@ describe("Code scanner widget tests", () => { propPane.TogglePropertyState("Disabled", "Off"); //Animate loading property - JS convertible - agHelper.AssertExistingToggleState("animateloading", "true"); + agHelper.AssertExistingToggleState("Animate loading", "true"); propPane.EnterJSContext( "Animate loading", "{{(45>55)?false:true}}", @@ -147,7 +147,7 @@ describe("Code scanner widget tests", () => { "{{(45>55)?false:true}}", ); propPane.EnterJSContext("Animate loading", "", false, true); - propPane.ToggleJSMode("animateloading", false); + propPane.ToggleJSMode("Animate loading", false); // Text & tooltip properties agHelper.AssertElementVisibility(widgetLocators.codeScannerScanButton); @@ -255,23 +255,23 @@ describe("Code scanner widget tests", () => { }); //skipping below test as it is not able to scan this code in CI even after 60Sec of wait, works fine in local - Need to be picked later - it.skip("8. Validate scanning broken/damaged QR code.", () => { - //Open the Code Scanner modal and Scan broken/damaged QR code using fake webcam video - cy.task("changeVideoSource", "brokenQRCode.y4m"); - agHelper.RefreshPage("viewPage"); - agHelper.AssertElementVisibility(widgetLocators.codeScannerNewScanButton); - agHelper.GetNClick(widgetLocators.codeScannerNewScanButton, 0, true); - agHelper.AssertElementVisibility(widgetLocators.codeScannerModal); + // it("8. Validate scanning broken/damaged QR code.", () => { + // //Open the Code Scanner modal and Scan broken/damaged QR code using fake webcam video + // cy.task("changeVideoSource", "brokenQRCode.y4m"); + // agHelper.RefreshPage("viewPage"); + // agHelper.AssertElementVisibility(widgetLocators.codeScannerNewScanButton); + // agHelper.GetNClick(widgetLocators.codeScannerNewScanButton, 0, true); + // agHelper.AssertElementVisibility(widgetLocators.codeScannerModal); - //Verify that the scanned data is correctly displayed on the app's screen - agHelper.AssertElementAbsence(widgetLocators.codeScannerModal, 60000); - agHelper.ValidateToastMessage("Code scanned using click to scan mode!"); - agHelper.AssertText( - locators._widgetInDeployed(draggableWidgets.TEXT), - "text", - "http://en.m.wikipedia.org", - ); - }); + // //Verify that the scanned data is correctly displayed on the app's screen + // agHelper.AssertElementAbsence(widgetLocators.codeScannerModal, 60000); + // agHelper.ValidateToastMessage("Code scanned using click to scan mode!"); + // agHelper.AssertText( + // locators._widgetInDeployed(draggableWidgets.TEXT), + // "text", + // "http://en.m.wikipedia.org", + // ); + // }); it("9. Validate scanning high density QR code.", () => { //Open the Code Scanner modal and Scan high density QR code using fake webcam video diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ContainerTest2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ContainerTest2_spec.ts new file mode 100644 index 0000000000..7ccc3ec036 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ContainerTest2_spec.ts @@ -0,0 +1,141 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Rich Text Editor widget Tests", function () { + before(() => { + agHelper.AddDsl("ContainerWithOtherWidgetsDsl"); + entityExplorer.SelectEntityByName("Container1", "Widgets"); + }); + + it("1. Verify property visibility", function () { + const generalProperties = ["visible", "animateloading", "height"]; + + const styleColorProperties = ["backgroundcolor", "bordercolor"]; + + const styleBorderProperties = ["borderwidth", "borderradius", "boxshadow"]; + + propPane.AssertPropertyVisibility(generalProperties, "general"); + propPane.MoveToTab("Style"); + propPane.AssertPropertyVisibility(styleColorProperties, "color"); + propPane.AssertPropertyVisibility(styleBorderProperties, "borderandshadow"); + propPane.MoveToTab("Content"); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer("Container1", "NewContainer", true); + agHelper.AssertElementVisibility(locators._widgetName("NewContainer")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.SelectEntityByName("NewContainer", "Widgets"); + agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{c}`); + agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{v}`); + agHelper.Sleep(1000); + entityExplorer.ExpandCollapseEntity("NewContainer"); + entityExplorer.AssertEntityPresenceInExplorer("NewContainerCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewContainerCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewContainer"); + propPane.DeleteWidgetFromPropertyPane("NewContainerCopy"); + }); + + it("3. Verify height changes according to child widget visibility", () => { + entityExplorer.SelectEntityByName("NewContainer", "Widgets"); + agHelper.AssertCSS( + locators._widgetInDeployed("newcontainer"), + "height", + "440px", + ); + entityExplorer.SelectEntityByName("List1", "Widgets"); + propPane.TogglePropertyState("visible", "Off"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertCSS( + locators._widgetInDeployed("newcontainer"), + "height", + "100px", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertCSS( + locators._widgetInDeployed("newcontainer"), + "height", + "100px", + ); + deployMode.NavigateBacktoEditor(); + + // Verify multiple widgets selected groups into single container + entityExplorer.SelectEntityByName("Input1", "Widgets", true); + entityExplorer.SelectEntityByName("Select1", "Widgets", true); + entityExplorer.SelectEntityByName("Text3", "Widgets", true); + agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{g}`); + agHelper.Sleep(1000); + entityExplorer.AssertEntityPresenceInExplorer("Container3"); + entityExplorer.DeleteWidgetFromEntityExplorer("Container3"); + }); + + it("4. Validate visible toggle", () => { + entityExplorer.SelectEntityByName("NewContainer", "Widgets"); + propPane.TogglePropertyState("visible", "Off"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence(locators._widgetInDeployed("newcontainer")); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._widgetInDeployed("newcontainer")); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewContainer", "Widgets"); + propPane.TogglePropertyState("visible", "On"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("newcontainer"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("newcontainer"), + ); + deployMode.NavigateBacktoEditor(); + + // Visible JS mode + entityExplorer.SelectEntityByName("NewContainer", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "false"); + + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("iconbuttonwidget"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewContainer", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "true"); + propPane.ToggleJSMode("Visible", false); + }); + + it("5. Validate auto height with limits", function () { + propPane.SelectPropertiesDropDown("height", "Auto Height with limits"); + agHelper.HoverElement(propPane._autoHeightLimitMin); + agHelper.AssertContains("Min-Height: 10 rows"); + agHelper.HoverElement(propPane._autoHeightLimitMax); + agHelper.AssertContains("Max-Height: 46 rows"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Container_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Container_spec.js index 53a1ec7473..19b6036def 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Container_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Container_spec.js @@ -41,7 +41,7 @@ describe("Container Widget Functionality", function () { .first() .click({ force: true }) .clear() - .type(widgetsPage.yellowColorHex); + .type(widgetsPage.yellowColorHex, { delay: 0 }); cy.get( `div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}']`, ) @@ -54,7 +54,7 @@ describe("Container Widget Functionality", function () { .first() .click({ force: true }) .clear() - .type(widgetsPage.greenColorHex); + .type(widgetsPage.greenColorHex, { delay: 0 }); cy.get(widgetsPage.containerD) .should("have.css", "background") .and( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInputTest.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInputTest.ts new file mode 100644 index 0000000000..ddb707fb2c --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/CurrencyInput/CurrencyInputTest.ts @@ -0,0 +1,353 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("CUrrency Input widget Tests", function () { + before(() => { + entityExplorer.DragDropWidgetNVerify("currencyinputwidget", 550, 100); + }); + + it("1. Verify property visibility", function () { + const dataProperties = [ + "defaultvalue", + "currency", + "allowcurrencychange", + "decimalsallowed", + ]; + + const labelProperties = ["text", "position"]; + + const validationsProperties = [ + "required", + "regex", + "valid", + "errormessage", + ]; + + const generalProperties = [ + "tooltip", + "placeholder", + "showsteparrows", + "visible", + "disabled", + "animateloading", + "autofocus", + "height", + ]; + + const eventsProperties = [ + "ontextchanged", + "onfocus", + "onblur", + "onsubmit", + "resetonsubmit", + ]; + + const labelStylesProperties = ["fontcolor", "fontsize"]; + + const borderShadows = ["borderradius", "boxshadow"]; + + entityExplorer.SelectEntityByName("CurrencyInput1", "Widgets"); + // Data section + dataProperties.forEach((dataSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("data", `${dataSectionProperty}`), + ); + }); + + // Label section + labelProperties.forEach((labelSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "label", + `${labelSectionProperty}`, + ), + ); + }); + + // Validation section + validationsProperties.forEach((validationSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "validation", + `${validationSectionProperty}`, + ), + ); + }); + + // General section + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + // Events section + eventsProperties.forEach((eventsSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "events", + `${eventsSectionProperty}`, + ), + ); + }); + + propPane.MoveToTab("Style"); + labelStylesProperties.forEach((labelStyleSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "labelstyles", + `${labelStyleSectionProperty}`, + ), + ); + }); + + borderShadows.forEach((borderShadowSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "borderandshadow", + `${borderShadowSectionProperty}`, + ), + ); + }); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "CurrencyInput1", + "NewCurrencyInput", + true, + ); + agHelper.AssertElementVisibility(locators._widgetName("NewCurrencyInput")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewCurrencyInput"); + entityExplorer.AssertEntityPresenceInExplorer("NewCurrencyInputCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewCurrencyInputCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewCurrencyInput"); + propPane.DeleteWidgetFromPropertyPane("NewCurrencyInputCopy"); + entityExplorer.SelectEntityByName("NewCurrencyInput", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("3. Verify Default value", () => { + entityExplorer.DragDropWidgetNVerify("textwidget", 550, 300); + propPane.UpdatePropertyFieldValue("Text", "1000"); + entityExplorer.SelectEntityByName("NewCurrencyInput", "Widgets"); + propPane.UpdatePropertyFieldValue("Default value", "{{Text1.text}}"); + agHelper.AssertText(locators._input, "val", "1,000"); + }); + + it("4. Verify allow currency change toggle", () => { + propPane.TogglePropertyState("allowcurrencychange", "On"); + agHelper.AssertElementVisibility(propPane._currencyChangeDropdownIcon); + propPane.TogglePropertyState("allowcurrencychange", "Off"); + agHelper.AssertElementAbsence(propPane._currencyChangeDropdownIcon); + }); + + it("5. Verify changing Label text and position", () => { + propPane.UpdatePropertyFieldValue("Text", "New Label"); + agHelper.AssertText(locators._label, "text", "New Label"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Left')`); + agHelper.AssertAttribute(locators._label, "position", "Left"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "position", "Left"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "position", "Left"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewCurrencyInput", "Widgets"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Top')`); + agHelper.AssertAttribute(locators._label, "position", "Top"); + }); + + it("6. Verify validation Regex, valid criteria and error message", () => { + // Regex validation + propPane.UpdatePropertyFieldValue("Regex", "^\\d{1,3}$"); + propPane.UpdatePropertyFieldValue("Error message", "Not valid value"); + agHelper.ClearNType(locators._input, "1234"); + agHelper.AssertPopoverTooltip("Not valid value"); + agHelper.ClearNType(locators._input, "100"); + agHelper.AssertElementAbsence(locators._popoverToolTip); + + // Valid option + propPane.UpdatePropertyFieldValue("Valid", "{{Text1.isVisible}}"); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.TogglePropertyState("visible", "Off"); + agHelper.GetNClick(locators._input); + agHelper.AssertPopoverTooltip("Not valid value"); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.TogglePropertyState("visible", "On"); + agHelper.GetNClick(locators._input); + agHelper.AssertElementAbsence(locators._popoverToolTip); + }); + + it("7. Verify tooltip", () => { + entityExplorer.SelectEntityByName("NewCurrencyInput", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "{{Text1.text}}"); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1000"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1000"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1000"); + deployMode.NavigateBacktoEditor(); + }); + + it("8. Validate 'visible', 'disable' and 'auto Focus' toggle", () => { + entityExplorer.SelectEntityByName("NewCurrencyInput"); + + // Verify Disabled toggle + propPane.TogglePropertyState("disabled", "On"); + agHelper.AssertAttribute( + locators._widgetInDeployed("currencyinputwidget"), + "disabled", + "disabled", + ); + propPane.TogglePropertyState("disabled", "Off"); + // Verify Visible toggle + propPane.TogglePropertyState("visible", "Off"); + agHelper.AssertAttribute( + locators._widgetInDeployed("currencyinputwidget"), + "data-hidden", + "true", + ); + agHelper.AssertExistingToggleState("visible", "false"); + propPane.TogglePropertyState("visible", "On"); + agHelper.AssertExistingToggleState("visible", "true"); + // Auto Focus + propPane.TogglePropertyState("autofocus", "On"); + agHelper.RefreshPage(); + agHelper.AssertElementFocus(locators._input); + }); + + it("9. Validate auto height with limits", function () { + propPane.SelectPropertiesDropDown("height", "Auto Height with limits"); + agHelper.HoverElement(propPane._autoHeightLimitMin); + agHelper.AssertContains("Min-Height: 4 rows"); + agHelper.HoverElement(propPane._autoHeightLimitMax); + agHelper.AssertContains("Max-Height: 9 rows"); + propPane.SelectPropertiesDropDown("height", "Auto Height"); + }); + + it("10. Validate events onTextChange, onFocus, OnBlur and OnSubmit", function () { + // onSubmit + propPane.SelectPlatformFunction("onSubmit", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value Submitted", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.ClearNType(locators._input, "101"); + agHelper.GetElement(locators._input).type("{enter}"); + agHelper.ValidateToastMessage("Value Submitted"); + + // onTextChange + propPane.SelectPlatformFunction("onTextChanged", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value Changed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.ClearNType(locators._input, "100"); + agHelper.ValidateToastMessage("Value Changed"); + + // onFocus + propPane.SelectPlatformFunction("onFocus", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value Focused", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.GetNClick(locators._input); + agHelper.ValidateToastMessage("Value Focused"); + + // OnBlur + propPane.SelectPlatformFunction("onBlur", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Blurred", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.GetNClick(locators._input); + agHelper.WaitUntilToastDisappear("Value Focused"); + agHelper.ClickOutside(); + agHelper.ValidateToastMessage("Blurred"); + }); + + it("11. Verify Full color picker and font size", () => { + // Verify font color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("fontcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("fontcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + // Font size + propPane.SelectPropertiesDropDown("fontsize", "L"); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "L"); + propPane.ToggleJSMode("fontsize", true); + propPane.UpdatePropertyFieldValue("Font size", "1rem"); + propPane.ToggleJSMode("fontsize", false); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "M"); + // Verify Emphasis + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.AssertAttribute(locators._label, "font-style", "BOLD"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + propPane.ToggleJSMode("emphasis", true); + propPane.UpdatePropertyFieldValue("Emphasis", "ITALIC"); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewCurrencyInput", "Widgets"); + propPane.MoveToTab("Style"); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS(".text-input-wrapper", "border-radius", "0px"); + + // Verify Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + agHelper.AssertCSS( + ".text-input-wrapper", + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Datepicker/DatePicker3_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Datepicker/DatePicker3_spec.ts new file mode 100644 index 0000000000..70b184f89d --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Datepicker/DatePicker3_spec.ts @@ -0,0 +1,299 @@ +import { + agHelper, + draggableWidgets, + entityExplorer, + deployMode, + propPane, + locators, + dataSources, +} from "../../../../../support/Objects/ObjectsCore"; + +import { format } from "date-fns"; +import { datePickerlocators } from "../../../../../locators/WidgetLocators"; + +describe("Date picker widget testcases", () => { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.DATEPICKER); + }); + + afterEach(() => { + deployMode.NavigateBacktoEditor(); + }); + + it("1. Sets and asserts a date format ", () => { + agHelper.GetNClick(propPane._selectPropDropdown("Date format")); + agHelper + .GetAttribute(datePickerlocators.options, "label", 7) + .then((dateFormatToSet: any) => { + agHelper.GetNClick(propPane._dropDownValue(dateFormatToSet), 0, true); + agHelper + .GetAttribute(datePickerlocators.input, "value") + .then((labelValue) => { + expect(labelValue).to.equal(dateFormatToSet); + }); + }); + + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.ClickButton("Clear"); + agHelper + .GetAttribute(datePickerlocators.input, "value") + .then((labelValue) => { + expect(labelValue).to.equal(""); + }); + agHelper.GetNClick(datePickerlocators.selectYear, 0, true); + + agHelper + .GetAttribute(datePickerlocators.dayPick, "aria-label") + .then((dateValueSet: any) => { + agHelper.GetNClick(datePickerlocators.dayPick); + agHelper.GetNClick(datePickerlocators.input); + agHelper + .GetAttribute(datePickerlocators.input, "value") + .then((labelValue) => { + const formattedDate = format( + new Date(dateValueSet), + "d MMMM, yyyy", + ); + expect(labelValue).to.contain(formattedDate); + }); + }); + }); + + it("2. Assert time precision - None, Minute, Second ", () => { + entityExplorer.SelectEntityByName("DatePicker1"); + + agHelper.GetNClick(propPane._selectPropDropdown("Date format")); + agHelper + .GetAttribute(datePickerlocators.options, "label", 0) + .then((dateFormatToSet: any) => { + agHelper.GetNClick(propPane._dropDownValue(dateFormatToSet), 0, true); + }); + propPane.SelectPropertiesDropDown("Time precision", "None"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.AssertElementAbsence(datePickerlocators.inputHour); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.SelectPropertiesDropDown("Time precision", "Minute"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.AssertElementExist(datePickerlocators.inputHour); + agHelper.AssertElementExist(datePickerlocators.inputMinute); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.SelectPropertiesDropDown("Time precision", "Second"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.ClearNType(datePickerlocators.inputHour, "12", 0, true); + agHelper.Sleep(500); // wait for the input to be updated for CI runs + agHelper.ClearNType(datePickerlocators.inputMinute, "58", 0, true); + agHelper.Sleep(500); // wait for the input to be updated for CI runs + agHelper.ClearNType(datePickerlocators.inputSecond, "59", 0, true); + agHelper.Sleep(500); // wait for the input to be updated for CI runs + agHelper.PressEnter(); + agHelper + .GetAttribute(datePickerlocators.input, "value") + .then((labelValue) => { + expect(labelValue).to.contain("12:58:59"); + }); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + + agHelper.GetNClick(propPane._selectPropDropdown("Date format")); + agHelper + .GetAttribute(datePickerlocators.options, "label", 15) + .then((dateFormatToSet: any) => { + agHelper.GetNClick(propPane._dropDownValue(dateFormatToSet), 0, true); + }); + propPane.SelectPropertiesDropDown("Time precision", "Second"); + + deployMode.DeployApp(); + + agHelper.GetNClick(datePickerlocators.input); + agHelper.ClearNType(datePickerlocators.inputHour, "12", 0, true); + agHelper.ClearNType(datePickerlocators.inputMinute, "58", 0, true); + agHelper.ClearNType(datePickerlocators.inputSecond, "59", 0, true); + agHelper.PressEnter(); + agHelper + .GetAttribute(datePickerlocators.input, "value") + .then((labelValue) => { + expect(labelValue).to.not.contain("12:58:59"); + }); + }); + + it("3. Assert First day of the week - (0-6) Sunday - Saturday ", () => { + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.UpdatePropertyFieldValue("First Day Of Week", "0"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + // assert is the first day is Sunday to last day is Saturday + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Su", + "have.text", + ); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Mo", + "have.text", + 1, + ); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Tu", + "have.text", + 2, + ); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "We", + "have.text", + 3, + ); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Th", + "have.text", + 4, + ); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Fr", + "have.text", + 5, + ); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Sa", + "have.text", + 6, + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + // Change the first day of the week to Monday and assert + propPane.UpdatePropertyFieldValue("First Day Of Week", "1"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Mo", + "have.text", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + // Change the first day of the week to Tuesday and assert + propPane.UpdatePropertyFieldValue("First Day Of Week", "2"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Tu", + "have.text", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.UpdatePropertyFieldValue("First Day Of Week", "3"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "We", + "have.text", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.UpdatePropertyFieldValue("First Day Of Week", "4"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Th", + "have.text", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.UpdatePropertyFieldValue("First Day Of Week", "5"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Fr", + "have.text", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.UpdatePropertyFieldValue("First Day Of Week", "6"); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.GetNAssertElementText( + datePickerlocators.weekDay, + "Sa", + "have.text", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + propPane.UpdatePropertyFieldValue("First Day Of Week", "7"); + agHelper.VerifyEvaluatedErrorMessage("Number should be between 0-6."); + propPane.UpdatePropertyFieldValue("First Day Of Week", "0"); + deployMode.DeployApp(); + }); + + it("4. Assert Min Date and Max Date set ", () => { + entityExplorer.SelectEntityByName("DatePicker1"); + // set min date + agHelper.GetNClick(locators._existingFieldTextByName("Min Date")); + agHelper.GetNClick(datePickerlocators.calendarHeader, 2); + agHelper.GetNClick(datePickerlocators.year("2022"), 0, true); + agHelper.GetNClick(datePickerlocators.calendarHeader, 1); + agHelper.GetNClick(dataSources._visibleTextSpan("Jan"), 0, true); + agHelper.GetNClick(datePickerlocators.date("001")); + // set max date + agHelper.GetNClick(locators._existingFieldTextByName("Max Date")); + agHelper.GetNClick(datePickerlocators.calendarHeader, 1); + agHelper.GetNClick(dataSources._visibleTextSpan("Feb"), 0, true); + agHelper.GetNClick(datePickerlocators.calendarHeader, 2); + agHelper.GetNClick(datePickerlocators.year("2023"), 0, true); + agHelper.GetNClick(datePickerlocators.date("010")); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + agHelper.GetNClick(datePickerlocators.selectYear, 0, true); + // check for only years between min and max date is present + agHelper.AssertElementExist(datePickerlocators.yearInDropdown("2022")); + agHelper.AssertElementExist(datePickerlocators.yearInDropdown("2023")); + agHelper.AssertElementAbsence(datePickerlocators.yearInDropdown("2000")); + agHelper.GetNClick(datePickerlocators.yearInDropdown("2022"), 0, true); + // check for months present between min and max date + agHelper.GetNClick(datePickerlocators.selectMonth, 0, true); + agHelper.AssertElementExist(datePickerlocators.monthInDropdown("January")); + agHelper.AssertElementExist(datePickerlocators.monthInDropdown("December")); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("DatePicker1"); + // set min date as same year as max date + agHelper.GetNClick(locators._existingFieldTextByName("Min Date")); + agHelper.GetNClick(datePickerlocators.calendarHeader, 2); + agHelper.GetNClick(datePickerlocators.year("2023"), 0, true); + agHelper.GetNClick(datePickerlocators.calendarHeader, 1); + agHelper.GetNClick(dataSources._visibleTextSpan("Jan"), 0, true); + agHelper.GetNClick(datePickerlocators.date("001")); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + // assert for months jan and feb as min and max date are set between them + agHelper.AssertElementExist(datePickerlocators.monthInDropdown("January")); + agHelper.AssertElementExist(datePickerlocators.monthInDropdown("February")); + agHelper.AssertElementAbsence(datePickerlocators.monthInDropdown("March")); + }); + + it("5. Assert onDateSelected action ", () => { + entityExplorer.SelectEntityByName("DatePicker1"); + // set an alert + propPane.SelectPlatformFunction("onDateSelected", "Show alert"); + agHelper.EnterActionValue("Message", "Date selected"); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + deployMode.DeployApp(); + agHelper.GetNClick(datePickerlocators.input); + // on date selection verify the toast set + agHelper.GetNClick(datePickerlocators.dayPick, 0, true); + agHelper.ValidateToastMessage("Date selected"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Divider/Divider_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Divider/Divider_spec.ts new file mode 100644 index 0000000000..79027b3c46 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Divider/Divider_spec.ts @@ -0,0 +1,145 @@ +import { + agHelper, + draggableWidgets, + entityExplorer, + deployMode, + propPane, + locators, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Divider Widget functionality tests", () => { + before(() => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.DIVIDER, 200, 200); + }); + + it("1. Divider widget Visiblity property verification", () => { + propPane.TogglePropertyState("Visible", "Off"); + // verify in deploy mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInCanvas(draggableWidgets.DIVIDER), + ); + deployMode.NavigateBacktoEditor(); + // verify in preview mode + agHelper.GetNClick(locators._enterPreviewMode); + //verify widget is not present + agHelper.AssertElementAbsence( + locators._widgetInCanvas(draggableWidgets.DIVIDER), + ); + //Exit preview mode + agHelper.GetNClick(locators._exitPreviewMode); + }); + + it("2. Divider widget style section verification", () => { + entityExplorer.SelectEntityByName("Divider1", "Widgets"); + propPane.TogglePropertyState("Visible", "On"); + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Color", "Purple"); + //propPane.SelectColorFromColorPicker("iconcolor", -15); + agHelper.AssertCSS( + widgetLocators.dividerHorizontal, + "border-top-color", + "rgb(128, 0, 128)", + ); + propPane.EnterJSContext("Style", "Dotted"); + agHelper.AssertCSS( + widgetLocators.dividerHorizontal, + "border-top-style", + "dotted", + ); + propPane.UpdatePropertyFieldValue("Thickness", "4"); + agHelper.AssertCSS( + widgetLocators.dividerHorizontal, + "border-top-width", + "4px", + ); + propPane.EnterJSContext("Cap", "dot"); + propPane.EnterJSContext("Direction", "vertical"); + agHelper.AssertElementAbsence(widgetLocators.dividerHorizontal); + agHelper.Sleep(1000); + }); + + it("3. Bind style properties of divider to radio widget and verify ", () => { + entityExplorer.DragDropWidgetNVerify( + draggableWidgets.RADIO_GROUP, + 400, + 400, + ); + entityExplorer.SelectEntityByName("Divider1", "Widgets"); + propPane.EnterJSContext( + "Direction", + "{{RadioGroup1.selectedOptionValue==='Y'?'horizontal':'vertical'}}", + ); + propPane.EnterJSContext( + "Color", + "{{RadioGroup1.selectedOptionValue==='Y'?'#231F20':'#b91c1c'}}", + ); + + propPane.EnterJSContext( + "Style", + "{{RadioGroup1.selectedOptionValue==='Y'?'solid':'dotted'}}", + ); + propPane.EnterJSContext( + "Cap", + "{{RadioGroup1.selectedOptionValue==='Y'?'nc':'dot'}}", + ); + agHelper.AssertExistingCheckedState(locators._checkboxTypeByOption("Yes")); + agHelper.AssertElementAbsence(widgetLocators.dividerVertical); + entityExplorer.SelectEntityByName("Divider1", "Widgets"); + agHelper.AssertCSS( + widgetLocators.dividerHorizontal, + "border-top-color", + "rgb(35, 31, 32)", + ); + agHelper.AssertCSS( + widgetLocators.dividerHorizontal, + "border-top-style", + "solid", + ); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + agHelper.CheckUncheck(locators._checkboxTypeByOption("No")); + agHelper.AssertElementAbsence(widgetLocators.dividerHorizontal); + agHelper.AssertCSS( + widgetLocators.dividerVertical, + "border-right-color", + "rgb(185, 28, 28)", + ); + agHelper.AssertCSS( + widgetLocators.dividerVertical, + "border-right-style", + "dotted", + ); + }); + + it("4. Verify bindings in preview and deploy mode", () => { + // verify in preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence(widgetLocators.dividerHorizontal); + agHelper.AssertCSS( + widgetLocators.dividerVertical, + "border-right-color", + "rgb(185, 28, 28)", + ); + agHelper.AssertCSS( + widgetLocators.dividerVertical, + "border-right-style", + "dotted", + ); + //Exit preview mode + agHelper.GetNClick(locators._exitPreviewMode); + // Enter view mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence(widgetLocators.dividerVertical); + agHelper.AssertCSS( + widgetLocators.dividerHorizontal, + "border-top-color", + "rgb(35, 31, 32)", + ); + agHelper.AssertCSS( + widgetLocators.dividerHorizontal, + "border-top-style", + "solid", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Filepicker/FilePicker3_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Filepicker/FilePicker3_spec.ts new file mode 100644 index 0000000000..95dd2280df --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Filepicker/FilePicker3_spec.ts @@ -0,0 +1,218 @@ +import { + agHelper, + locators, + entityExplorer, + deployMode, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Verify file picker widget", () => { + before(() => { + agHelper.AddDsl("filepickerDsl"); + }); + it("1. Verify property visibility", () => { + const basicProperties = [ + "allowedfiletypes", + "dataformat", + `maxno\\.offiles`, + ]; + + const labelProperties = ["text"]; + + const validationProperties = ["required", "maxfilesize\\(mb\\)"]; + + const generalProperties = ["visible", "disable", "animateloading"]; + + const eventsProperties = ["onfilesselected"]; + + const styleColorProperties = ["buttoncolor"]; + + const styleBorderProperties = ["borderradius", "boxshadow"]; + + entityExplorer.SelectEntityByName("FilePicker1", "Widgets"); + + propPane.AssertPropertyVisibility(basicProperties, "basic"); + propPane.AssertPropertyVisibility(labelProperties, "label"); + propPane.AssertPropertyVisibility(validationProperties, "validation"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + propPane.AssertPropertyVisibility(eventsProperties, "events"); + propPane.MoveToTab("Style"); + propPane.AssertPropertyVisibility(styleColorProperties, "color"); + propPane.AssertPropertyVisibility(styleBorderProperties, "borderandshadow"); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "FilePicker1", + "NewFilePicker", + true, + ); + agHelper.AssertElementVisibility(locators._widgetName("NewFilePicker")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewFilePicker"); + entityExplorer.AssertEntityPresenceInExplorer("NewFilePickerCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewFilePickerCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewFilePicker"); + propPane.DeleteWidgetFromPropertyPane("NewFilePickerCopy"); + entityExplorer.SelectEntityByName("NewFilePicker", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("3. Verify max number of files", () => { + agHelper.AssertText(locators._buttonText, "text", "Select Files"); + propPane.UpdatePropertyFieldValue("Max no. of files", "2"); + agHelper.ClickButton("Select Files"); + agHelper.UploadFile("AAAFlowerVase.jpeg"); + // Verify Add more is visible + agHelper.GetNClick(locators._buttonInDeployedMode, 0, true); + agHelper.AssertElementVisibility(locators._fileUploadAddMore); + agHelper.GetNClick(locators._fileUploadAddMore); + + // Verify Add more does not exist when max no. files are added + agHelper.UploadFile("appsmithlogo.png"); + agHelper.GetNClick(locators._buttonInDeployedMode, 0, true); + agHelper.AssertElementAbsence(locators._fileUploadAddMore); + agHelper.GetNClick(locators._fileUploadDashboardClose); + + agHelper.AssertText(locators._buttonText, "text", "2 files selected"); + }); + + it("4. Verify Validation max file size supported", () => { + propPane.UpdatePropertyFieldValue("Max file size(Mb)", "1"); + agHelper.GetNClick(locators._buttonInDeployedMode, 0, true); + agHelper.GetNClick('[title="Remove file"]'); + agHelper.GetNClick(locators._fileUploadAddMore); + agHelper + .GetElement(locators._uploadFiles) + .eq(0) + .selectFile("cypress/fixtures/Appsmith.gif", { force: true }) + .wait(3000); + agHelper.AssertElementVisibility( + locators._fileUploadErrorContains( + "This file exceeds maximum allowed size of 1 MB ", + ), + ); + agHelper.GetNClick(locators._fileUploadDashboardClose); + }); + + it("5. Validate visible and disabled toggle", () => { + propPane.TogglePropertyState("visible", "Off"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("filepickerwidgetv2"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("filepickerwidgetv2"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewFilePicker", "Widgets"); + propPane.TogglePropertyState("visible", "On"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("filepickerwidgetv2"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("filepickerwidgetv2"), + ); + deployMode.NavigateBacktoEditor(); + + // Visible JS mode + entityExplorer.SelectEntityByName("NewFilePicker", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "false"); + + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("filepickerwidgetv2"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewFilePicker", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "true"); + propPane.ToggleJSMode("Visible", false); + + // Disabled + propPane.TogglePropertyState("disable", "On"); + agHelper.AssertAttribute( + locators._widgetInDeployed("filepickerwidgetv2"), + "disabled", + "disabled", + ); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute( + locators._widgetInDeployed("filepickerwidgetv2"), + "disabled", + "disabled", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute( + locators._widgetInDeployed("filepickerwidgetv2"), + "disabled", + "disabled", + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewFilePicker", "Widgets"); + propPane.TogglePropertyState("disable", "Off"); + }); + + it("6. Verify onFilesSelected", () => { + propPane.ToggleJSMode("onFilesSelected", true); + propPane.UpdatePropertyFieldValue( + "onFilesSelected", + "{{showAlert('File Selected', '');}}", + ); + deployMode.DeployApp(); + agHelper.ClickButton("Select Files"); + agHelper.UploadFile("appsmithlogo.png"); + agHelper.ValidateToastMessage("File Selected"); + deployMode.NavigateBacktoEditor(); + }); + + it("7. Verify button color and border and shadows", () => { + entityExplorer.SelectEntityByName("NewFilePicker", "Widgets"); + // Verify button color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("buttoncolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("buttoncolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS(locators._buttonInDeployedMode, "border-radius", "0px"); + + // Verify Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + agHelper.AssertCSS( + locators._buttonInDeployedMode, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_Select_TreeSelect_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_Select_TreeSelect_spec.js index f0f9bb411d..251784a198 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_Select_TreeSelect_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_Select_TreeSelect_spec.js @@ -1,16 +1,21 @@ const widgetsPage = require("../../../../../locators/Widgets.json"); const formWidgetsPage = require("../../../../../locators/FormWidgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { agHelper } from "../../../../../support/Objects/ObjectsCore"; describe("Form Widget Functionality", function () { before(() => { - _.agHelper.AddDsl("formSelectTreeselectDsl"); + agHelper.AddDsl("formSelectTreeselectDsl"); }); + it("Validate Select and TreeSelect Widget", function () { cy.get(widgetsPage.formButtonWidget) .contains("Submit") .should("have.attr", "disabled"); - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(1000) //for dropdown to load for CI runs + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); cy.get(formWidgetsPage.treeSelectFilterInput).click().type("Blue"); cy.treeSelectDropdown("Blue"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_spec.js index f6ea4ef9ff..f7cdbfeed7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Form/FormWidget_spec.js @@ -114,6 +114,7 @@ describe("Form Widget Functionality", function () { cy.get(publish.formWidget).should("be.visible"); _.deployMode.NavigateBacktoEditor(); }); + it("5. Toggle JS - Form-Unckeck Visible field Validation", function () { cy.openPropertyPane("formwidget"); //Uncheck the disabled checkbox using JS and validate @@ -130,12 +131,13 @@ describe("Form Widget Functionality", function () { cy.testJsontext("visible", "true"); _.deployMode.DeployApp(); cy.get(publish.formWidget).should("be.visible"); + _.deployMode.NavigateBacktoEditor(); }); - it.skip("6. Form-Copy Verification", function () { + it("6. Form-Copy Verification", function () { cy.openPropertyPane("formwidget"); //Copy Form and verify all properties - cy.copyWidget("formwidget", widgetsPage.formWidget); //to improve + cy.copyWidget("formwidget", widgetsPage.formWidget); _.deployMode.DeployApp(); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Iframe/IframeTest_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Iframe/IframeTest_spec.ts new file mode 100644 index 0000000000..de45a3f2c6 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Iframe/IframeTest_spec.ts @@ -0,0 +1,139 @@ +import { + agHelper, + locators, + entityExplorer, + propPane, + deployMode, +} from "../../../../../support/Objects/ObjectsCore"; + +import testdata from "../../../../../fixtures/testdata.json"; + +describe("Iframe widget Tests", function () { + before(() => { + entityExplorer.DragDropWidgetNVerify("iframewidget", 550, 100); + }); + + const srcDoc = ` + + + + + Simple Iframe Widget Test + + + + + + `; + + const getIframeBody = () => { + return cy + .get(".t--draggable-iframewidget iframe") + .its("0.contentDocument.body") + .should("not.be.empty") + .then(cy.wrap); + }; + + it("1. Verify content and user interaction", function () { + propPane.UpdatePropertyFieldValue("URL", testdata.iframeUrl); + getIframeBody() + .find(".header-logo") + .should("have.attr", "href", testdata.iframeUrlSubstring); + + // Title + propPane.UpdatePropertyFieldValue("Title", "Test Title"); + agHelper.AssertAttribute( + ".t--draggable-iframewidget iframe", + "title", + "Test Title", + ); + + // User interaction - Click + getIframeBody().find(locators._pageHeaderToggle).click({ force: true }); + getIframeBody().find(locators._pageHeaderMenuList).should("be.visible"); + getIframeBody().find(locators._pageHeaderToggle).click({ force: true }); + getIframeBody().find(locators._pageHeaderMenuList).should("not.be.visible"); + + // Full screen + getIframeBody().find(locators._enterFullScreen).click({ force: true }); + getIframeBody() + .find(locators._dashboardContainer) + .should( + "have.class", + "application-demo-new-dashboard-container-fullscreen", + ); + getIframeBody().find(locators._exitFullScreen).click({ force: true }); + getIframeBody() + .find(locators._dashboardContainer) + .should( + "not.have.class", + "application-demo-new-dashboard-container-fullscreen", + ); + }); + + it("2. Verify onMessageReceived, onSrcDocChanged, onURLChanged", function () { + // onMessageReceived + propPane.SelectPlatformFunction("onMessageReceived", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Message Received", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + getIframeBody() + .find("a:contains('Social Feed')") + .first() + .click({ force: true }); + agHelper.ValidateToastMessage("Message Received"); + + // onSrcDocChanged + propPane.SelectPlatformFunction("onSrcDocChanged", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value Changed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + propPane.UpdatePropertyFieldValue("srcDoc", srcDoc); + agHelper.ValidateToastMessage("Value Changed"); + getIframeBody() + .find("iframe") + .its("0.contentDocument.body") + .find("p") + .should("have.text", "This is a simple srcdoc content."); + + // onURLChanged + propPane.SelectPlatformFunction("onURLChanged", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "URL Changed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + propPane.UpdatePropertyFieldValue("URL", testdata.iframeRandomUrl); + agHelper.ValidateToastMessage("URL Changed"); + }); + + it("3. Verify colors, borders and shadows", () => { + propPane.MoveToTab("Style"); + + // Change Border Color + propPane.SelectColorFromColorPicker("bordercolor", 10); + + // Change border + agHelper.GetNClick(propPane._segmentedControl("0px")); + + // Change Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + + //Verify details in Deploy mode + deployMode.DeployApp(); + //agHelper.AssertCSS("iframe", "border-color", "rgb(185, 28, 28)"); + agHelper.AssertCSS("iframe", "border-radius", "0px"); + agHelper.AssertCSS( + "iframe", + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image2_Spec.ts new file mode 100644 index 0000000000..0c53bf72b5 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image2_Spec.ts @@ -0,0 +1,201 @@ +import { + agHelper, + draggableWidgets, + deployMode, + entityExplorer, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Image widget tests", function () { + const image = (src: string) => 'img[src="' + src + '"]'; + const jpgImg = "https://jpeg.org/images/jpegsystems-home.jpg"; + const gifImg = + "https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/5eeea355389655.59822ff824b72.gif"; + const svgImg = "https://assets.codepen.io/3/kiwi.svg"; + const webpImg = "https://www.gstatic.com/webp/gallery/4.sm.webp"; + const pngImg = "https://assets.appsmith.com/widgets/default.png"; + + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.IMAGE); + }); + + it("1. Verify Image Preview for different types of images (png, jpg, gif, svg, webp)", function () { + //jpg + propPane.UpdatePropertyFieldValue("Image", jpgImg); + agHelper.AssertAttribute(widgetLocators.image + " img", "src", jpgImg); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementExist(image(jpgImg)); + agHelper.AssertContains("Unable to display the image", "not.exist"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + //gif + propPane.UpdatePropertyFieldValue("Image", gifImg); + agHelper.AssertAttribute(widgetLocators.image + " img", "src", gifImg); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementExist(image(gifImg)); + agHelper.AssertContains("Unable to display the image", "not.exist"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + //webp + propPane.UpdatePropertyFieldValue("Image", webpImg); + agHelper.AssertAttribute(widgetLocators.image + " img", "src", webpImg); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementExist(image(webpImg)); + agHelper.AssertContains("Unable to display the image", "not.exist"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + //Not working in cypress whereas works fine manually + //svg + // propPane.UpdatePropertyFieldValue("Image", svgImg); + // agHelper.AssertAttribute(widgetLocators.image + " img", "src", svgImg) + // deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + // agHelper.AssertElementExist(image(svgImg)) + // agHelper.AssertContains("Unable to display the image", "not.exist") + // deployMode.NavigateBacktoEditor(); + // entityExplorer.SelectEntityByName("Image1", "Widgets"); + //png + propPane.UpdatePropertyFieldValue("Image", pngImg); + agHelper.AssertAttribute(widgetLocators.image + " img", "src", pngImg); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementExist(image(pngImg)); + agHelper.AssertContains("Unable to display the image", "not.exist"); + }); + + it("2. Validate Binding Image to Button Widget and checking the behaviour on enabling/disabling the button", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.UpdatePropertyFieldValue( + "Image", + "{{Button1.isDisabled ?'" + jpgImg + "':'" + gifImg + "'}}", + ); + entityExplorer.DragNDropWidget(draggableWidgets.BUTTON, 200, 400); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementExist(image(gifImg)); + agHelper.AssertContains("Unable to display the image", "not.exist"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.TogglePropertyState("Disabled", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementExist(image(jpgImg)); + agHelper.AssertContains("Unable to display the image", "not.exist"); + }); + + it("3. Verify Zoom In property", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.AssertPropertiesDropDownCurrentValue( + "Max zoom level", + "1x (No Zoom)", + ); + propPane.AssertPropertiesDropDownValues("Max zoom level", [ + "1x (No Zoom)", + "2x", + "4x", + "8x", + "16x", + ]); + propPane.SelectPropertiesDropDown("Max zoom level", "16x"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertCSS(widgetLocators.image, "cursor", "zoom-in"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.EnterJSContext("Max zoom level", "{{(55>45)?1:16}}", true, true); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper + .GetElement(widgetLocators.image) + .should("not.have.css", "cursor", "zoom-in"); + }); + + it("4. Verify Object fit property", function () { + agHelper.AssertCSS(widgetLocators.image, "background-size", "cover"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.AssertPropertiesDropDownCurrentValue("Object fit", "Cover"); + propPane.AssertPropertiesDropDownValues("Object fit", [ + "Contain", + "Cover", + "Auto", + ]); + propPane.SelectPropertiesDropDown("Object fit", "Contain"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertCSS(widgetLocators.image, "background-size", "contain"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.EnterJSContext( + "Object fit", + "{{(55>45)?auto:contain}}", + true, + true, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertCSS(widgetLocators.image, "background-size", "auto"); + }); + + it("5. Verify visible property is JS convertible", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.EnterJSContext("Visible", "{{(55>45)?false:true}}", true, true); + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.IMAGE), + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.EnterJSContext("Visible", "{{(45>55)?false:true}}", false, true); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + }); + + it("6. Verify image styles", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Border radius", "", true, true); + agHelper.AssertElementVisibility(widgetLocators.styleOrangeIcon); + agHelper.AssertElementVisibility(widgetLocators.styleResetBtn); + agHelper.GetNClick(widgetLocators.styleResetBtn); + agHelper.AssertContains( + "{{appsmith.theme.borderRadius.appBorderRadius}}", + "be.visible", + ); + propPane.ToggleJSMode("borderradius", false); + agHelper.ContainsNClick("Medium"); + propPane.EnterJSContext("Border radius", "24px"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertCSS( + locators._widgetInDeployed(draggableWidgets.IMAGE) + " > div > div > div", + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px", + ); + agHelper.AssertCSS( + locators._widgetInDeployed(draggableWidgets.IMAGE) + " > div > div > div", + "border-radius", + "24px", + ); + }); + + it("7. Validate OnClick Event", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.EnterJSContext( + "onClick", + "{{showAlert('Image Clicked!','success')}}", + true, + ); + propPane.ToggleJSMode("onClick", false); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.ValidateToastMessage("Image Clicked!"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + propPane.SelectPlatformFunction("onClick", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Image Clicked again!", + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.ValidateToastMessage("Image Clicked again!"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image3_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image3_Spec.ts new file mode 100644 index 0000000000..172bef451f --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image3_Spec.ts @@ -0,0 +1,62 @@ +import { + agHelper, + draggableWidgets, + deployMode, + entityExplorer, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Image widget - Rotation & Download", function () { + const jpgImg = "https://jpeg.org/images/jpegsystems-home.jpg"; + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.IMAGE); + propPane.UpdatePropertyFieldValue("Image", jpgImg); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + }); + + it("1. Validate enable rotation property", function () { + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementAbsence(widgetLocators.imageRotateClockwiseBtn); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + agHelper.AssertExistingToggleState("Enable rotation", "false"); + propPane.TogglePropertyState("Enable rotation", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.Sleep(2000); //for widget to settle loading + agHelper.HoverElement(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementVisibility(widgetLocators.imageRotateClockwiseBtn); + agHelper.AssertElementVisibility( + widgetLocators.imageRotateAntiClockwiseBtn, + ); + agHelper.GetHoverNClick(widgetLocators.imageRotateClockwiseBtn); + agHelper.AssertCSS( + widgetLocators.image, + "transform", + "matrix(0, 1, -1, 0, 0, 0)", + ); + agHelper.GetHoverNClick(widgetLocators.imageRotateAntiClockwiseBtn); + agHelper.AssertCSS( + widgetLocators.image, + "transform", + "matrix(1, 0, 0, 1, 0, 0)", + ); + }); + + it("2. Verify image download", function () { + agHelper.HoverElement(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementAbsence(widgetLocators.imageDownloadBtn); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Image1", "Widgets"); + agHelper.AssertExistingToggleState("Enable download", "false"); + propPane.TogglePropertyState("Enable download", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.Sleep(2000); //for widget to settle loading + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.HoverElement(locators._widgetInDeployed(draggableWidgets.IMAGE)); + agHelper.AssertElementVisibility(widgetLocators.imageDownloadBtn); + agHelper.AssertAttribute(widgetLocators.imageDownloadBtn, "href", jpgImg); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js index f720049454..5ebd0c7dfb 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js @@ -65,18 +65,7 @@ describe("Image Widget Functionality", function () { deployMode.NavigateBacktoEditor(); }); - it("4. Image Widget Functionality To check download option and validate image link", function () { - cy.openPropertyPane("imagewidget"); - cy.togglebar(".t--property-control-enabledownload input[type='checkbox']"); - cy.get(publish.imageWidget).trigger("mouseover"); - cy.get(`${publish.imageWidget} a[data-testid=t--image-download]`).should( - "have.attr", - "href", - this.dataSet.NewImage, - ); - }); - - it("5. In case of an image loading error, show off the error message", () => { + it("4. In case of an image loading error, show off the error message", () => { cy.openPropertyPane("imagewidget"); // Invalid image url const invalidImageUrl = "https://www.example.com/does-not-exist.jpg"; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ImperativeStoreUpdate_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ImperativeStoreUpdate_spec.ts new file mode 100644 index 0000000000..b8570da4fc --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ImperativeStoreUpdate_spec.ts @@ -0,0 +1,50 @@ +import { + PROPERTY_SELECTOR, + WIDGET, + getWidgetSelector, +} from "../../../../locators/WidgetLocators"; + +import { + entityExplorer, + jsEditor, + agHelper, + locators, + propPane, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Linting warning for imperative store update", function () { + it("Shows lint error for imperative store update", function () { + entityExplorer.DragDropWidgetNVerify(WIDGET.BUTTON, 200, 200); + entityExplorer.DragDropWidgetNVerify(WIDGET.TEXT, 400, 400); + + agHelper.GetNClick(getWidgetSelector(WIDGET.BUTTON)); + propPane.TypeTextIntoField("Label", "{{appsmith.store.name = 6}}"); + + //Mouse hover to exact warning message + agHelper.AssertElementVisibility(locators._lintErrorElement); + agHelper.HoverElement(locators._lintErrorElement); + agHelper.AssertContains("Use storeValue() method to modify the store"); + agHelper.Sleep(); + + //Create a JS object + jsEditor.CreateJSObject( + `export default { + myFun1: () => { + appsmith.store.name.text = 6 + }, + }`, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }, + ); + + agHelper.AssertElementVisibility(locators._lintErrorElement); + agHelper.HoverElement(locators._lintErrorElement); + agHelper.AssertContains("Use storeValue() method to modify the store"); + agHelper.Sleep(); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input2_Spec.ts new file mode 100644 index 0000000000..ed413ce895 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input2_Spec.ts @@ -0,0 +1,344 @@ +import { + agHelper, + draggableWidgets, + deployMode, + entityExplorer, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("InputV2 widget tests", function () { + let testcases, + multilineData = `[ + { + "label": "Blue", + "value": "Blue" + }, + { + "label": "Green", + "value": "Green" + }, + { + "label": "Red", + "value": "RED" + } + ]`; + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.INPUT_V2); + }); + + it("1. Data Type - Single Line Text", function () { + propPane.AssertPropertiesDropDownCurrentValue( + "Data type", + "Single-line text", + ); + propPane.AssertPropertiesDropDownValues("Data type", [ + "Single-line text", + "Multi-line text", + "Number", + "Password", + "Email", + ]); + + //Assert that it doesn't display textarea for single line text + agHelper.AssertElementAbsence( + locators._widgetInCanvas(draggableWidgets.INPUT_V2) + " textarea", + ); + + //Default value + propPane.UpdatePropertyFieldValue("Default value", "Enter input"); + + //Position + agHelper.AssertAttribute( + locators._position("Top"), + "data-selected", + "true", + ); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-bottom", "5px"); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-right", "0px"); + agHelper.GetNClick(locators._position("Left")); + agHelper.AssertAttribute( + locators._position("Left"), + "data-selected", + "true", + ); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + + //Assert that it doesn't display textarea for single line text + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "Enter input", + ); + agHelper.AssertCSS( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "height", + "30px", + ); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-bottom", "0px"); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-right", "5px"); + + //Validate special characters & symbols + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "!@#$56&*().,:", + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "!@#$56&*().,:", + ); + + //Assert widget height after text input + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + multilineData, + ); + agHelper.AssertCSS( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "height", + "30px", + ); + }); + + it("2. Data Type - Multi Line Text", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.SelectPropertiesDropDown("Data type", "Multi-line text"); + + //Assert that it should display textarea for multi line text + agHelper.AssertElementVisibility( + locators._widgetInCanvas(draggableWidgets.INPUT_V2) + " textarea", + ); + + //Default value + propPane.UpdatePropertyFieldValue( + "Default value", + "Enter multi line input", + ); + + //Position + agHelper.AssertAttribute( + locators._position("Left"), + "data-selected", + "true", + ); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-bottom", "0px"); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-right", "5px"); + agHelper.GetNClick(locators._position("Auto")); + agHelper.AssertAttribute( + locators._position("Auto"), + "data-selected", + "true", + ); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + + //Assert that it should display textarea for multi line text + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + ); + agHelper.AssertContains( + "Enter multi line input", + "be.visible", + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + ); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-bottom", "5px"); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "margin-right", "0px"); + agHelper.AssertCSS( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + "height", + "62px", + ); + + //Validate text formatting + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + multilineData, + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + "text", + multilineData, + ); + + //Assert widget height after text input + agHelper.AssertCSS( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + "height", + "314px", + ); + }); + + it("3. Data Type - Number", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.SelectPropertiesDropDown("Data type", "Number"); + + //Default value + propPane.UpdatePropertyFieldValue("Default value", "0"); + + //Min + propPane.UpdatePropertyFieldValue("Min", "-1"); + + //Max + propPane.UpdatePropertyFieldValue("Max", "1000000"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "0", + ); + + //Validate characters, decimals & negative numbers + testcases = [ + { + input: "!@#$56&*(),:", + expected: "56", + }, + { + input: "0.12356578909", + expected: "0.12356578909", + }, + { + input: "-0.12356578909", + expected: "-0.12356578909", + }, + ]; + testcases.forEach((testcase) => { + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + testcase.input, + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + testcase.expected, + ); + }); + + //Validation for minimum and maximum values + testcases = ["-12", "-1.1", "1000080", "1000000.001"]; + testcases.forEach((value) => { + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + value, + ); + agHelper.AssertPopoverTooltip("Invalid input"); + }); + + testcases = ["-0.99", "-1", "1000000", "999999.999"]; + testcases.forEach((value) => { + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + value, + ); + agHelper.AssertContains( + "Invalid input", + "not.exist", + locators._popoverToolTip, + ); + }); + }); + + it("4. Data Type - Password", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.SelectPropertiesDropDown("Data type", "Password"); + + //Default value + propPane.UpdatePropertyFieldValue("Default value", "1234"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "1234", + ); + + //Validate password is masked + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "password@123", + ); + agHelper.AssertAttribute( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "type", + "password", + ); + agHelper.AssertProperty( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "nodeName", + "INPUT", + ); + //Unmask password + agHelper.GetNClick(widgetLocators.inputWidgetUnMaskPassword); + agHelper.AssertAttribute( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "type", + "text", + ); + }); + + it("5. Data Type - Email", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.SelectPropertiesDropDown("Data type", "Email"); + + //Default value + propPane.UpdatePropertyFieldValue("Default value", "test@gmail.com"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "test@gmail.com", + ); + + //Validate different email formats + testcases = [ + "user1@example.com", + "user2@subdomain.example", + "test3@outlook.in", + ]; + testcases.forEach((email) => { + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + email, + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + email, + ); + agHelper.AssertContains( + "Invalid input", + "not.exist", + locators._popoverToolTip, + ); + }); + + //Invalid email validation + testcases = [ + "user1@example", + "user2@subdomain.", + "test3outlook.in", + "testmail", + ]; + testcases.forEach((email) => { + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + email, + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + email, + ); + agHelper.AssertPopoverTooltip("Invalid input"); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input3_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input3_Spec.ts new file mode 100644 index 0000000000..bd101fa403 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input3_Spec.ts @@ -0,0 +1,224 @@ +import { + agHelper, + draggableWidgets, + deployMode, + entityExplorer, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("InputV2 widget tests - continuation", function () { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.INPUT_V2); + }); + + it("1. Validate Required field", function () { + propPane.TogglePropertyState("Required", "On"); + propPane.UpdatePropertyFieldValue("Default value", ""); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.TypeText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "test", + ); + agHelper.ClearTextField( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + ); + agHelper.AssertPopoverTooltip("This field is required"); + }); + + it("2. Validate Max Characters (Single & Multi Line Text)", function () { + //Single line text input + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.SelectPropertiesDropDown("Data type", "Single-line text"); + propPane.UpdatePropertyFieldValue("Max characters", "10"); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "Hello! How are you?", + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "Hello! How", + ); + + //Multi line text input + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.SelectPropertiesDropDown("Data type", "Multi-line text"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + "Hello! How are you?", + ); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + "text", + "Hello! How", + ); + }); + + it("3. Validate Valid property", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.UpdatePropertyFieldValue("Valid", "{{Input1.text.length > 5}}"); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + "test", + ); + agHelper.AssertPopoverTooltip("Invalid input"); + }); + + it("4. Validate tooltip & onTextChangedEvent", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "Input tooltip"); + propPane.EnterJSContext( + "onTextChanged", + "{{showAlert('Text changed!','success')}}", + true, + ); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("Input tooltip"); + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " textarea", + "test", + ); + agHelper.ValidateToastMessage("Text changed!"); + }); + + it("5. Validate showStepArrows for number input", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.SelectPropertiesDropDown("Data type", "Number"); + agHelper.AssertElementAbsence(widgetLocators.inputWidgetStepUp); + agHelper.AssertElementAbsence(widgetLocators.inputWidgetStepDown); + propPane.TogglePropertyState("Show step arrows", "On"); + propPane.UpdatePropertyFieldValue("Min", "-1"); + propPane.UpdatePropertyFieldValue("Max", "10"); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.AssertElementVisibility(widgetLocators.inputWidgetStepUp); + agHelper.AssertElementVisibility(widgetLocators.inputWidgetStepDown); + + //Step arrows are disabled when input value equals max value or min value + agHelper.TypeText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "10", + ); + agHelper.AssertClassExists( + widgetLocators.inputWidgetStepUp, + "bp3-disabled", + ); + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "-1", + ); + agHelper.AssertClassExists( + widgetLocators.inputWidgetStepDown, + "bp3-disabled", + ); + + //Validate functionality of arrows + agHelper.GetNClick(widgetLocators.inputWidgetStepUp); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "0", + ); + agHelper.GetNClick(widgetLocators.inputWidgetStepDown); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "-1", + ); + }); + + it("6. Verify Input widget styles", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.SelectColorFromColorPicker("fontcolor", 11); + propPane.SelectPropertiesDropDown("Font size", "M"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.ContainsNClick("Medium"); + agHelper.GetNClick(locators._borderRadius("1.5rem")); + agHelper + .GetWidgetCSSFrAttribute(widgetLocators.inputWidgetLabel, "color") + .then((color) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.INPUT_V2), + ); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "color", color); + agHelper.AssertCSS( + widgetLocators.inputWidgetLabel, + "font-size", + "16px", + ); + agHelper.AssertCSS( + widgetLocators.inputWidgetLabel, + "font-weight", + "700", + ); + }); + agHelper.AssertCSS( + widgetLocators.inputWidgetWrapper, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px", + ); + agHelper.AssertCSS( + widgetLocators.inputWidgetWrapper, + "border-radius", + "24px", + ); + + //JS conversion + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Input1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Font color", "#22c55e"); + propPane.EnterJSContext("Font size", "1.25rem"); + agHelper.GetNClick(propPane._emphasisSelector("ITALIC")); + propPane.EnterJSContext("Border radius", "1rem"); + propPane.EnterJSContext( + "Box shadow", + "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)", + ); + agHelper + .GetWidgetCSSFrAttribute(widgetLocators.inputWidgetLabel, "color") + .then((color) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.INPUT_V2), + ); + agHelper.AssertCSS(widgetLocators.inputWidgetLabel, "color", color); + agHelper.AssertCSS( + widgetLocators.inputWidgetLabel, + "font-size", + "20px", + ); + agHelper.AssertCSS( + widgetLocators.inputWidgetLabel, + "font-style", + "italic", + ); + }); + agHelper.AssertCSS( + widgetLocators.inputWidgetWrapper, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px", + ); + agHelper.AssertCSS( + widgetLocators.inputWidgetWrapper, + "border-radius", + "16px", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input_spec.js index a113119ce7..2f752ef602 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/Input_spec.js @@ -164,21 +164,6 @@ describe("Input Widget Functionality", function () { cy.get(".bp3-icon-add").first().click({ force: true }); cy.get(".bp3-input-group .bp3-icon-add").should("exist"); }); - - it("8. Input value of number type should reflect the default text value 0", () => { - cy.moveToContentTab(); - cy.selectDropdownValue(widgetsPage.datatype, "Number"); - /*cy.get(widgetsPage.defaultInput) - .click({ force: true }) - .type("0");*/ - cy.testJsontext("defaultvalue", "0"); - cy.closePropertyPane("inputwidgetv2"); - cy.get(widgetsPage.innertext) - .invoke("val") - .then((text) => { - expect(text).to.equal("0"); - }); - }); }); afterEach(() => { // put your clean up code if any diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/RTL_support.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/RTL_support.ts new file mode 100644 index 0000000000..9370fb7400 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Input/RTL_support.ts @@ -0,0 +1,51 @@ +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; +import { + agHelper, + draggableWidgets, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Select Widget", () => { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.INPUT_V2); + }); + + it("1. Test RTL support", () => { + featureFlagIntercept({ + license_widget_rtl_support_enabled: false, + }); + + agHelper.AssertElementAbsence(".t--property-control-enablertl"); + + featureFlagIntercept({ + license_widget_rtl_support_enabled: true, + }); + + agHelper.RefreshPage(); + + agHelper.Sleep(2000); + + agHelper.AssertElementExist(".t--property-control-enablertl"); + + propPane.TogglePropertyState("Enable RTL", "On"); + + agHelper.AssertElementExist( + ".t--widget-inputwidgetv2 .bp3-input-group.rtl", + ); + + agHelper.AssertElementExist( + ".t--widget-inputwidgetv2 .label-container[dir='rtl']", + ); + + propPane.TogglePropertyState("Enable RTL", "Off"); + + agHelper.AssertElementAbsence( + ".t--widget-inputwidgetv2 .bp3-input-group.rtl", + ); + + agHelper.AssertElementAbsence( + ".t--widget-inputwidgetv2 .label-container[dir='rtl']", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_ArrayField_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_ArrayField_spec.js index e0dc8f4c31..c70fd9d8c4 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_ArrayField_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_ArrayField_spec.js @@ -4,19 +4,25 @@ const fieldPrefix = ".t--jsonformfield"; const education = `${fieldPrefix}-education`; const addButton = ".t--jsonformfield-array-add-btn"; const deleteButton = ".t--jsonformfield-array-delete-btn"; -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + entityExplorer, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; describe("JSON Form Widget Array Field", () => { beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); }); afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); it("1. can remove default items when default value changes from undefined to an array", () => { - _.agHelper.AddDsl("jsonFormDslWithSchemaAndWithoutSourceData"); + agHelper.AddDsl("jsonFormDslWithSchemaAndWithoutSourceData"); const sourceData = { name: "John", @@ -36,9 +42,9 @@ describe("JSON Form Widget Array Field", () => { }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); - cy.closePropertyPane(); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + deployMode.DeployApp(); cy.get(`${education} ${addButton}`).click({ force: true }); cy.get(`${education}-item`).should("have.length", 2); @@ -64,13 +70,15 @@ describe("JSON Form Widget Array Field", () => { ); cy.get(`${education}-0--year input`).should("have.value", "10/08/2010"); }); + + deployMode.NavigateBacktoEditor(); }); it("2. can add more items to the field", () => { cy.addDsl(dslWithSchema); cy.openPropertyPane("jsonformwidget"); - + cy.get(locators._jsToggle("sourcedata")).click({ force: true }); cy.get(`${education}-item`) .should("have.length", 1) .first() @@ -139,26 +147,33 @@ describe("JSON Form Widget Array Field", () => { it("4. can change the visibility of the field", () => { cy.get(education).should("exist"); - + agHelper.AssertElementExist(education); + entityExplorer.SelectEntityByName("JSONForm1"); cy.openPropertyPane("jsonformwidget"); cy.openFieldConfiguration("education"); // Visible -> false - cy.togglebarDisable(".t--property-control-visible input"); - cy.get(education).should("not.exist"); + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(education); + deployMode.NavigateBacktoEditor(); // Visible -> true - cy.togglebar(".t--property-control-visible input"); - cy.get(education).should("exist"); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("education"); + + propPane.TogglePropertyState("Visible", "On"); + agHelper.AssertElementExist(education); }); it("5. disables all underlying field when array field is disabled", () => { - cy.closePropertyPane(); - cy.openPropertyPane("jsonformwidget"); + entityExplorer.SelectEntityByName("JSONForm1"); cy.openFieldConfiguration("education"); // Disable -> true - cy.togglebar(".t--property-control-disabled input"); + propPane.TogglePropertyState("Disabled", "On"); + // cy.togglebar(".t--property-control-disabled input"); + deployMode.DeployApp(); cy.get(education) .first() .within(() => { @@ -166,8 +181,11 @@ describe("JSON Form Widget Array Field", () => { cy.get(`${education}-0--year input`).should("have.attr", "disabled"); }); - // Disable -> false - cy.togglebarDisable(".t--property-control-disabled input"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("education"); + propPane.TogglePropertyState("Disabled", "Off"); + // cy.togglebarDisable(".t--property-control-disabled input"); cy.get(education).should("exist"); cy.get(education) .first() @@ -184,8 +202,7 @@ describe("JSON Form Widget Array Field", () => { }); it("6. disables add new and remove buttons when array field is disabled", () => { - cy.closePropertyPane(); - cy.openPropertyPane("jsonformwidget"); + entityExplorer.SelectEntityByName("JSONForm1"); cy.openFieldConfiguration("education"); let initialNoOfItems = 0; @@ -194,7 +211,9 @@ describe("JSON Form Widget Array Field", () => { }); // Disable -> true - cy.togglebar(".t--property-control-disabled input"); + propPane.TogglePropertyState("Disabled", "On"); + deployMode.DeployApp(); + // cy.togglebar(".t--property-control-disabled input"); cy.get(`${education} ${addButton}`).should("have.attr", "disabled"); cy.get(`${education} ${addButton}`).should("have.attr", "disabled"); @@ -209,8 +228,13 @@ describe("JSON Form Widget Array Field", () => { expect($items.length).equal(initialNoOfItems); }); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("education"); + propPane.TogglePropertyState("Disabled", "Off"); + + deployMode.DeployApp(); // Disable -> false - cy.togglebarDisable(".t--property-control-disabled input"); cy.get(addButton).should("not.have.attr", "disabled"); cy.get(deleteButton).should("not.have.attr", "disabled"); // Click add button @@ -223,13 +247,13 @@ describe("JSON Form Widget Array Field", () => { cy.get(`${education}-item`).then(($items) => { expect($items.length).equal(initialNoOfItems); }); + deployMode.NavigateBacktoEditor(); }); it("7. should not render field level default value if form level is present", () => { const collegeFieldDefaultValue = "College default value"; - cy.closePropertyPane(); - cy.openPropertyPane("jsonformwidget"); + entityExplorer.SelectEntityByName("JSONForm1"); cy.openFieldConfiguration("education") .openFieldConfiguration("__array_item__", false) @@ -269,9 +293,7 @@ describe("JSON Form Widget Array Field", () => { }); it("8. phone input dropdown should update the selected value", () => { - cy.closePropertyPane(); - cy.openPropertyPane("jsonformwidget"); - + entityExplorer.SelectEntityByName("JSONForm1"); cy.openFieldConfiguration("education"); cy.openFieldConfiguration("__array_item__", false); @@ -293,6 +315,7 @@ describe("JSON Form Widget Array Field", () => { // Change the label of the field to Phone Number cy.testJsontext("text", "Phone Number"); + deployMode.DeployApp(); // Open country code dropdown and select +91 cy.get(".t--input-country-code-change").first().click(); cy.get(".t--search-input input").type("+91"); @@ -300,12 +323,11 @@ describe("JSON Form Widget Array Field", () => { cy.get(".t--dropdown-option").contains("+91").click({ force: true }); cy.get(".t--input-country-code-change").should("contain", "🇮🇳+91"); + deployMode.NavigateBacktoEditor(); }); it("9. currency input dropdown should update the selected value", () => { - cy.closePropertyPane(); - cy.openPropertyPane("jsonformwidget"); - + entityExplorer.SelectEntityByName("JSONForm1"); cy.openFieldConfiguration("education"); cy.openFieldConfiguration("__array_item__", false); @@ -324,6 +346,7 @@ describe("JSON Form Widget Array Field", () => { // Change the label of the field to Phone Number cy.testJsontext("text", "Currency"); + deployMode.DeployApp(); // Open country code dropdown and select gbp cy.get(".t--input-currency-change").first().click(); cy.get(".t--search-input input").type("gbp"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js index c8a5c1976d..0708559e60 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js @@ -1,21 +1,27 @@ const fieldPrefix = ".t--jsonformfield"; -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + entityExplorer, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; describe("JSON Form Widget AutoGenerate Disabled", () => { + before(() => { + agHelper.AddDsl("jsonFormDslWithSchemaAndWithoutSourceData"); + }); beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); }); afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); it("generates fields with valid source data json", () => { - _.agHelper.AddDsl("jsonFormDslWithSchemaAndWithoutSourceData"); - - cy.openPropertyPane("jsonformwidget"); - - cy.togglebarDisable(`.t--property-control-autogenerateform input`); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.TogglePropertyState("Auto generate form", "Off"); const sourceData = { name: "John", @@ -37,9 +43,9 @@ describe("JSON Form Widget AutoGenerate Disabled", () => { ], }; - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); - cy.closePropertyPane(); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + deployMode.DeployApp(); // Fields that should exist cy.get(`${fieldPrefix}-name label`).contains("Name"); @@ -108,15 +114,11 @@ describe("JSON Form Widget AutoGenerate Disabled", () => { cy.get(`${fieldPrefix}-education-0--course label`).should("not.exist"); cy.get(`${fieldPrefix}-education-0--course input`).should("not.exist"); + + deployMode.NavigateBacktoEditor(); }); it("modifies field when generate form button is pressed", () => { - _.agHelper.AddDsl("jsonFormDslWithSchemaAndWithoutSourceData"); - - cy.openPropertyPane("jsonformwidget"); - - cy.togglebarDisable(`.t--property-control-autogenerateform input`); - const sourceData = { name: "John", age: 30, @@ -137,15 +139,10 @@ describe("JSON Form Widget AutoGenerate Disabled", () => { ], }; - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); - - cy.wait(500); - cy.openPropertyPane("jsonformwidget"); - cy.get(".t--property-control-") - .contains("Generate form") - .click({ force: true }); - cy.closePropertyPane(); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + propPane.TogglePropertyState("Auto generate form", "On"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name label`).contains("Name"); cy.get(`${fieldPrefix}-name input`).should("have.value", "John"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js index 1c65985294..ddc938d33e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js @@ -1,8 +1,14 @@ const dslWithoutSchema = require("../../../../../fixtures/jsonFormDslWithoutSchema.json"); const jsonFormDslWithSchemaAndWithoutSourceData = require("../../../../../fixtures/jsonFormDslWithSchemaAndWithoutSourceData.json"); const fieldPrefix = ".t--jsonformfield"; +import { + entityExplorer, + deployMode, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; let agHelper = ObjectsRegistry.AggregateHelper; +let locators = ObjectsRegistry.CommonLocators; describe("JSON Form Widget AutoGenerate Enabled", () => { beforeEach(() => { @@ -32,9 +38,9 @@ describe("JSON Form Widget AutoGenerate Enabled", () => { ], }; - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); - cy.closePropertyPane(); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name label`).contains("Name"); cy.get(`${fieldPrefix}-name input`).then((input) => { @@ -90,6 +96,8 @@ describe("JSON Form Widget AutoGenerate Enabled", () => { cy.get( `${fieldPrefix}-education .t--jsonformfield-array-add-btn .t--text`, ).should("have.text", "Add New"); + + deployMode.NavigateBacktoEditor(); }); it("modifies field when source data changes", () => { @@ -115,8 +123,12 @@ describe("JSON Form Widget AutoGenerate Enabled", () => { }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(modifiedSourceData)); - cy.closePropertyPane(); + propPane.EnterJSContext( + "Source data", + JSON.stringify(modifiedSourceData), + true, + ); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name label`).contains("Name"); cy.get(`${fieldPrefix}-name input`).should("have.value", "John"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js index c0de91a0bd..3ee3ad5d30 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js @@ -2,13 +2,27 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); const explorer = require("../../../../../locators/explorerlocators.json"); const widgetsPage = require("../../../../../locators/Widgets.json"); const jsonform = require("../../../../../locators/jsonFormWidget.json"); +import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; +const { + deployMode, + entityExplorer, + locators, + propPane, +} = require("../../../../../support/Objects/ObjectsCore"); describe("JsonForm widget basis c usecases", function () { - it("Validate Drag and drop jsonform widget", function () { + before(() => { cy.get(explorer.addWidget).click(); cy.dragAndDropToCanvas("jsonformwidget", { x: 200, y: 200 }); - cy.openPropertyPane("jsonformwidget"); - cy.get(widgetsPage.jsonFormWidget).should("have.length", 1); + cy.fixture("TestDataSet1").then(function (dataSet) { + cy.openPropertyPane("jsonformwidget"); + propPane.EnterJSContext( + "Source data", + JSON.stringify(dataSet.defaultSource), + true, + ); + cy.get(widgetsPage.jsonFormWidget).should("have.length", 1); + }); }); it("json form widget validate default data", function () { @@ -28,7 +42,7 @@ describe("JsonForm widget basis c usecases", function () { }); it("json form widget validate reset button function", function () { - cy.openPropertyPane("jsonformwidget"); + deployMode.DeployApp(); cy.get(jsonform.jsformInput).clear({ force: true }); cy.get(jsonform.jsformInput).type("TestReset"); cy.get(jsonform.jsformEmpID).clear({ force: true }); @@ -50,9 +64,11 @@ describe("JsonForm widget basis c usecases", function () { "have.value", this.dataSet.defaultSource.employee_id, ); + deployMode.NavigateBacktoEditor(); }); it("Validate copy/paste/delete widget ", function () { + entityExplorer.SelectEntityByName("JSONForm1"); const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; //copy and paste cy.openPropertyPane("jsonformwidget"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CurrencyField_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CurrencyField_spec.ts index 42a3a5f0dc..38181af557 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CurrencyField_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CurrencyField_spec.ts @@ -9,10 +9,18 @@ import { } from "../../../../../support/Objects/ObjectsCore"; describe("Modal Widget background color spec", () => { + const schema = { + name: "John", + date_of_birth: "20/02/1990", + employee_id: 1001, + }; + before(() => { // Add a JSON form widget and change field type of one of the fields entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 300, 100); + propPane.EnterJSContext("sourcedata", JSON.stringify(schema), true, false); propPane.ChangeJsonFormFieldType("Employee Id", "Currency Input"); + propPane.NavigateBackToPropertyPane(); }); it("1. should check that value entered in currency field appears in the actual field", () => { @@ -20,9 +28,21 @@ describe("Modal Widget background color spec", () => { * This case is for checking the following bug: https://github.com/appsmithorg/appsmith/issues/23671 * This issue introduced a behaviour by which for currency field type in JSON form, users where not able to enter/type any value into it. **/ - agHelper - .GetElement(locators._jsonFormInputField("employee_id")) - .type("123"); + + propPane.SelectPlatformFunction("onSubmit", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "{{JSONForm1.formData.employee_id.toString()}}", + ); + deployMode.DeployApp(); + + agHelper.TypeText( + locators._jsonFormInputField("employee_id"), + "123 konnichiwa", + ); + agHelper.Sleep(500); + agHelper.ClickButton("Submit"); + agHelper.ValidateToastMessage("1001123"); agHelper .GetText(locators._jsonFormInputField("employee_id"), "val") .should("be.equal", "1001123"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CustomField_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CustomField_spec.js index 9d5cab3eba..d7beb5d532 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CustomField_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_CustomField_spec.js @@ -1,5 +1,12 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); const jsonFormDslWithSchemaAndWithoutSourceData = require("../../../../../fixtures/jsonFormDslWithSchemaAndWithoutSourceData.json"); +import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; +const locators = ObjectsRegistry.CommonLocators; +const { + deployMode, + entityExplorer, + propPane, +} = require("../../../../../support/Objects/ObjectsCore"); const fieldPrefix = ".t--jsonformfield"; @@ -45,9 +52,10 @@ describe("JSON Form Widget Custom Field", () => { ], }; - cy.openPropertyPane("jsonformwidget"); - cy.backFromPropertyPanel(); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.NavigateBackToPropertyPane(); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + deployMode.DeployApp(); cy.wait(500); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldChange_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldChange_spec.js index 6adc1864a5..302fb9a76c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldChange_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldChange_spec.js @@ -1,56 +1,84 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); const dslWithSchema = require("../../../../../fixtures/jsonFormDslWithSchema.json"); - +import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; +const locators = ObjectsRegistry.CommonLocators; +const { + agHelper, + deployMode, + entityExplorer, + propPane, +} = require("../../../../../support/Objects/ObjectsCore"); +import { datePickerlocators } from "../../../../../locators/WidgetLocators"; const fieldPrefix = ".t--jsonformfield"; describe("JSON Form Widget Field Change", () => { before(() => { cy.addDsl(dslWithSchema); }); + it("1. modifies field type text to number", () => { cy.openPropertyPane("jsonformwidget"); - + cy.get(locators._jsToggle("sourcedata")).click({ force: true }); cy.get(`${fieldPrefix}-name`).find("button").should("not.exist"); cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Number Input"); + propPane.NavigateBackToPropertyPane(); + propPane.SelectPlatformFunction("onSubmit", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "{{JSONForm1.formData.name.toString()}}", + ); + deployMode.DeployApp(); + agHelper.TypeText(datePickerlocators.input, "123"); + agHelper.Sleep(500); + agHelper.ClickButton("Submit"); + agHelper.ValidateToastMessage("123"); + agHelper.TypeText(datePickerlocators.input, "konnichiwa"); + agHelper.ClickButton("Submit"); + agHelper.CheckForErrorToast( + "Cannot read properties of null (reading 'toString')", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); cy.get(`${fieldPrefix}-name`).find("button").should("have.length", 2); + cy.openPropertyPane("jsonformwidget"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("2. modifies field type text to checkbox", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-name`) .find("input") .invoke("attr", "type") .should("contain", "text"); cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Checkbox"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`) .find("input") .invoke("attr", "type") .should("contain", "checkbox"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("3. modifies field type text to date", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-name`).find("input").click({ force: true }); cy.get(".bp3-popover.bp3-dateinput-popover").should("not.exist"); cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Datepicker"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`).find("input").click({ force: true }); cy.get(".bp3-popover.bp3-dateinput-popover").should("exist"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("4. modifies field type text to switch", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-name`) .find(".bp3-control.bp3-switch") .should("not.exist"); @@ -58,70 +86,65 @@ describe("JSON Form Widget Field Change", () => { cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Switch"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`) .find(".bp3-control.bp3-switch") .should("exist"); - + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("5. modifies field type text to Multi-Select", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-name`) .find(".rc-select-multiple") .should("not.exist"); cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Multiselect"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`).find(".rc-select-multiple").should("exist"); - + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("6. modifies field type text to Radio-Group", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-name`) .find(".bp3-control.bp3-radio") .should("not.exist"); cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Radio Group"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`) .find(".bp3-control.bp3-radio") .should("exist") .should("have.length", 2); - + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("7. modifies field type text to Array", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-name`) .find(".t--jsonformfield-array-add-btn") .should("not.exist"); cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Array"); - cy.wait(2000); - /* - cy.get(`${fieldPrefix}-name`) - .find(".t--jsonformfield-array-add-btn") - .should("exist"); - */ + deployMode.DeployApp(); cy.get('button span:contains("Add New")').first().should("be.visible"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("8. modifies field type text to Object", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Object"); cy.get(`${fieldPrefix}-name`).find("input").should("not.exist"); @@ -130,22 +153,22 @@ describe("JSON Form Widget Field Change", () => { force: true, }); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`).find("input").should("exist"); - + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("9. modifies field type Multi-Select to Array", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-hobbies`) .find(".rc-select-multiple") .should("exist"); cy.openFieldConfiguration("hobbies"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Array"); - cy.wait(2000); //for array field to reflect + deployMode.DeployApp(); cy.get(`${fieldPrefix}-hobbies`).then((hobbies) => { cy.wrap(hobbies).find(".t--jsonformfield-array-add-btn").should("exist"); cy.wrap(hobbies).find("input").should("have.length", 2); @@ -153,14 +176,13 @@ describe("JSON Form Widget Field Change", () => { .find(".t--jsonformfield-array-delete-btn") .should("have.length", 2); }); - + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Text Input/); - //cy.closePropertyPane(); }); it("10. modifies field type text to Select", () => { - //cy.openPropertyPane("jsonformwidget"); - cy.get(`${fieldPrefix}-name label`).click({ force: true }); cy.get(".bp3-select-popover.select-popover-wrapper").should("not.exist"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_1_spec.js index 0f020921d3..ab17e588d0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_1_spec.js @@ -4,41 +4,44 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); const widgetLocators = require("../../../../../locators/Widgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + propPane, + entityExplorer, + locators, +} from "../../../../../support/Objects/ObjectsCore"; const fieldPrefix = ".t--jsonformfield"; const toggleJSButton = (name) => `.t--property-control-${name} .t--js-toggle`; describe("Radio Group Field", () => { beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); }); afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); - it("1. Radio Group Field - pre condition", () => { + it("1. Set radio group pre condition and show alert on optionChange", () => { const schema = { answer: "Y", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + agHelper.AddDsl("jsonFormDslWithoutSchema"); + + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("answer"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Radio Group"); - cy.closePropertyPane(); - }); - - it("2. shows alert on optionChange", () => { - cy.openPropertyPane("jsonformwidget"); - cy.openFieldConfiguration("answer"); - // Enable JS mode for onSelectionChange - cy.get(toggleJSButton("onselectionchange")).click({ force: true }); + propPane.EnterJSContext( + "onSelectionChange", + "{{showAlert(formData.answer)}}", + ); - // Add onSelectionChange action - cy.testJsontext("onselectionchange", "{{showAlert(formData.answer)}}"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-answer`) .find("label") @@ -46,17 +49,17 @@ describe("Radio Group Field", () => { .click({ force: true }); // Check for alert - cy.get(commonlocators.toastmsg).contains("N"); + agHelper.ValidateToastMessage("N"); + deployMode.NavigateBacktoEditor(); }); - it("3. Multiselect Field - pre condition", () => { + it("2. Shows updated formData values in onOptionChange binding", () => { const schema = { colors: ["BLUE"], }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); - cy.closePropertyPane(); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + // cy.closePropertyPane(); }); it("4. Shows updated formData values in onOptionChange binding", () => { @@ -64,14 +67,12 @@ describe("Radio Group Field", () => { cy.openFieldConfiguration("colors"); // Enable JS mode for onOptionChange - cy.get(toggleJSButton("onoptionchange")).click({ force: true }); - - // Add onOptionChange action - cy.testJsontext( - "onoptionchange", + propPane.EnterJSContext( + "onOptionChange", "{{showAlert(formData.colors.join(', '))}}", ); + deployMode.DeployApp(); // Click on multiselect field cy.get(`${fieldPrefix}-colors`) .find(".rc-select-selection-search-input") @@ -82,30 +83,23 @@ describe("Radio Group Field", () => { // Check for alert cy.get(commonlocators.toastmsg).contains("BLUE, RED"); + deployMode.NavigateBacktoEditor(); }); - it("5. Select Field - pre condition", () => { + it("3. shows updated formData values in onOptionChange binding", () => { const schema = { color: "BLUE", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + agHelper.AddDsl("jsonFormDslWithoutSchema"); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("color"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Select/); - cy.closePropertyPane(); - }); - - it("6. shows updated formData values in onOptionChange binding", () => { - cy.openPropertyPane("jsonformwidget"); - cy.openFieldConfiguration("color"); - - // Enable JS mode for onOptionChange - cy.get(toggleJSButton("onoptionchange")).click({ force: true }); // Add onOptionChange action - cy.testJsontext("onoptionchange", "{{showAlert(formData.color)}}"); - + propPane.EnterJSContext("onOptionChange", "{{showAlert(formData.color)}}"); + deployMode.DeployApp(); // Click on select field cy.get(`${fieldPrefix}-color`) .find(widgetLocators.dropdownSingleSelect) @@ -118,28 +112,23 @@ describe("Radio Group Field", () => { // Check for alert cy.get(commonlocators.toastmsg).contains("RED"); + deployMode.NavigateBacktoEditor(); }); - it("7. Input Field - pre condition", () => { + it("4. Shows updated formData values in onOptionChange binding", () => { const schema = { name: "John", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); - cy.closePropertyPane(); - }); + agHelper.AddDsl("jsonFormDslWithoutSchema"); - it("8. Shows updated formData values in onOptionChange binding", () => { - cy.openPropertyPane("jsonformwidget"); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); cy.openFieldConfiguration("name"); - // Enable JS mode for onTextChanged - cy.get(toggleJSButton("ontextchanged")).click({ force: true }); - // Add onTextChanged action - cy.testJsontext("ontextchanged", "{{showAlert(formData.name)}}"); + propPane.EnterJSContext("onTextChanged", "{{showAlert(formData.name)}}"); + deployMode.DeployApp(); // Change input value cy.get(`${fieldPrefix}-name`).click(); cy.get(`${fieldPrefix}-name`).type(" Doe"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_2_spec.js index 49a5b65992..b5a28642d5 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldEvents_2_spec.js @@ -3,101 +3,93 @@ */ const commonlocators = require("../../../../../locators/commonlocators.json"); -const widgetLocators = require("../../../../../locators/Widgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + entityExplorer, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; const fieldPrefix = ".t--jsonformfield"; const toggleJSButton = (name) => `.t--property-control-${name} .t--js-toggle`; describe("Radio Group Field", () => { beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); }); afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); - it("1. Checkbox Field - pre condition", () => { + it("1. Shows updated formData values in onChange binding", () => { const schema = { agree: true, }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + agHelper.AddDsl("jsonFormDslWithoutSchema"); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("agree"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Checkbox/); - cy.closePropertyPane(); + + propPane.EnterJSContext( + "onCheckChange", + "{{showAlert(formData.agree.toString())}}", + ); + deployMode.DeployApp(); + // Click on select field + cy.get(`${fieldPrefix}-agree input`).click({ force: true }); + + // Check for alert + cy.get(commonlocators.toastmsg).contains("false"); + + deployMode.NavigateBacktoEditor(); }); it("2. Shows updated formData values in onChange binding", () => { - cy.openPropertyPane("jsonformwidget"); - cy.openFieldConfiguration("agree"); - - // Enable JS mode for onCheckChange - cy.get(toggleJSButton("oncheckchange")).click({ force: true }); - - // Add onCheckChange action - cy.testJsontext( - "oncheckchange", - "{{showAlert(formData.agree.toString())}}", - ); - - // Click on select field - cy.get(`${fieldPrefix}-agree input`).click({ force: true }); - - // Check for alert - cy.get(commonlocators.toastmsg).contains("false"); - }); - - it("3. Switch Field - pre condition", () => { const schema = { agree: true, }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); - cy.closePropertyPane(); - }); + agHelper.AddDsl("jsonFormDslWithoutSchema"); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); - it("4. Shows updated formData values in onChange binding", () => { - cy.openPropertyPane("jsonformwidget"); cy.openFieldConfiguration("agree"); - // Enable JS mode for onChange - cy.get(toggleJSButton("onchange")).click({ force: true }); - - // Add onChange action - cy.testJsontext("onchange", "{{showAlert(formData.agree.toString())}}"); + propPane.EnterJSContext( + "onChange", + "{{showAlert(formData.agree.toString())}}", + ); + deployMode.DeployApp(); // Click on select field cy.get(`${fieldPrefix}-agree input`).click({ force: true }); // Check for alert cy.get(commonlocators.toastmsg).contains("false"); + + deployMode.NavigateBacktoEditor(); }); - it("5. Date Field - pre condition", () => { + it("3. shows updated formData values in onDateSelected binding", () => { const schema = { dob: "20/12/1992", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); + agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); - cy.closePropertyPane(); - }); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); - it("6. shows updated formData values in onDateSelected binding", () => { - cy.openPropertyPane("jsonformwidget"); cy.openFieldConfiguration("dob"); // Enable JS mode for onDateSelected cy.get(toggleJSButton("ondateselected")).click({ force: true }); - // Add onDateSelected action - cy.testJsontext("ondateselected", "{{showAlert(formData.dob)}}"); + propPane.EnterJSContext("onDateSelected", "{{showAlert(formData.dob)}}"); + deployMode.DeployApp(); // Click on select field cy.get(`${fieldPrefix}-dob .bp3-input`).click(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_1_spec.js index 4578e857ac..a8eb75ade1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_1_spec.js @@ -1,51 +1,58 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + entityExplorer, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; const fieldPrefix = ".t--jsonformfield"; describe("Text Field Property Control", () => { beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); }); afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); before(() => { const schema = { name: "John", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); + agHelper.AddDsl("jsonFormDslWithoutSchema"); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + entityExplorer.SelectEntityByName("JSONForm1"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); }); - it("1. has valid default text", () => { + it("1. updated field with change in default text", () => { + // check name has valid default text cy.openFieldConfiguration("name"); cy.get(".t--property-control-defaultvalue").contains("{{sourceData.name}}"); - }); - - it("2. updated field with change in default text", () => { const defaultValue = "New default text"; - cy.testJsontext("defaultvalue", "New default text").wait(200); + propPane.UpdatePropertyFieldValue("Default value", defaultValue); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name input`).should("have.value", defaultValue); + deployMode.NavigateBacktoEditor(); }); - it("3. throws max character error when exceeds maxChar limit for default text", () => { - cy.testJsontext("maxchars", 5); + it("2. throws max character error when exceeds maxChar limit for default text and input text", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); + cy.testJsontext("maxchars", 5).wait(200); cy.get(`${fieldPrefix}-name input`).click(); cy.get(".bp3-popover-content").should(($x) => { expect($x).contain( "Default text length must be less than or equal to 5 characters", ); }); - cy.testJsontext("maxchars", ""); - }); - - it("4. throws max character error when exceeds maxChar limit for input text", () => { - cy.testJsontext("defaultvalue", "").wait(200); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); + cy.testJsontext("maxchars", "").wait(200); + cy.testJsontext("defaultvalue", 5).wait(200); cy.get(`${fieldPrefix}-name input`).clear().type("abcdefghi"); cy.testJsontext("maxchars", 5).wait(200); cy.get(`${fieldPrefix}-name input`).click(); @@ -55,22 +62,37 @@ describe("Text Field Property Control", () => { cy.testJsontext("maxchars", ""); }); - it("5. sets placeholder", () => { + it("3. sets placeholder", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + const placeholderText = "First name"; cy.testJsontext("placeholder", placeholderText); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name input`) .invoke("attr", "placeholder") .should("contain", placeholderText); + deployMode.NavigateBacktoEditor(); }); - it("6. sets valid property with custom error message", () => { + it("4. sets valid property with custom error message", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.testJsontext("valid", "false"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name input`).clear().type("abcd"); cy.get(".bp3-popover-content").contains("Invalid input"); - + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.testJsontext("errormessage", "Custom error message"); + + deployMode.DeployApp(); + cy.get(`${fieldPrefix}-name input`).clear().type("yuru camp"); cy.get(`${fieldPrefix}-name input`).click({ force: true }); cy.get(".bp3-popover-content").contains("Custom error message"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); // Reset the error message cy.testJsontext("errormessage", ""); @@ -78,71 +100,89 @@ describe("Text Field Property Control", () => { cy.testJsontext("valid", ""); }); - it("7. hides field when visible switched off", () => { - cy.togglebarDisable(`.t--property-control-visible input`); + it("5. hides field when visible switched off", () => { + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`).should("not.exist"); - cy.wait(500); - cy.togglebar(`.t--property-control-visible input`); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); + propPane.TogglePropertyState("Visible", "On"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name`).should("exist"); + deployMode.NavigateBacktoEditor(); }); - it("8. disables field when disabled switched on and when autofill is disabled we should see the autofill attribute in the input field", () => { + it("6. disables field when disabled switched on and when autofill is disabled we should see the autofill attribute in the input field", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.togglebar(`.t--property-control-disabled input`); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name input`).each(($el) => { cy.wrap($el).should("have.attr", "disabled"); }); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.togglebarDisable(`.t--property-control-disabled input`); validateAutocompleteAttributeInJSONForm(); }); - it("9. throws error when REGEX does not match the input value", () => { + it("7. throws error when REGEX does not match the input value", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("name"); cy.testJsontext("regex", "^\\d+$"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-name input`).clear().type("abcd"); cy.get(".bp3-popover-content").contains("Invalid input"); cy.get(`${fieldPrefix}-name input`).clear().type("1234"); cy.get(".bp3-popover-content").should("not.exist"); + deployMode.NavigateBacktoEditor(); }); - it("10. Checkbox Field Property Control - pre condition", () => { + it("8. Checkbox Field Property Control - pre condition", () => { const schema = { check: false, }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); + agHelper.AddDsl("jsonFormDslWithoutSchema"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); cy.openFieldConfiguration("check"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Checkbox"); - }); - - it("11. has default property", () => { + // check deafult property cy.get(".t--property-control-defaultstate").contains( "{{sourceData.check}}", ); }); - it("12. should update field checked state when default selected changed", () => { + it("9. should update field checked state when default selected changed", () => { + //should update field checked state when default selected changed cy.testJsontext("defaultstate", "{{true}}"); cy.get(`${fieldPrefix}-check input`).should("be.checked"); - }); - it("13. hides field when visible switched off", () => { + // hides field when visible switched off cy.togglebarDisable(`.t--property-control-visible input`); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-check`).should("not.exist"); - cy.wait(500); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("check"); cy.togglebar(`.t--property-control-visible input`); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-check`).should("exist"); - }); + deployMode.NavigateBacktoEditor(); - it("14. disables field when disabled switched on", () => { + // disables field when disabled switched on + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("check"); cy.togglebar(`.t--property-control-disabled input`); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-check input`).each(($el) => { cy.wrap($el).should("have.attr", "disabled"); }); - - cy.togglebarDisable(`.t--property-control-disabled input`); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_2_spec.js index 4738487b05..538d74cdf0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FieldProperties_2_spec.js @@ -1,88 +1,106 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + entityExplorer, + deployMode, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; const fieldPrefix = ".t--jsonformfield"; describe("Text Field Property Control", () => { beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); }); afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); before(() => { const schema = { name: "John", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); - + agHelper.AddDsl("jsonFormDslWithoutSchema"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); }); it("1. Switch Field Property Control - pre condition", () => { const schema = { switch: true, }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); + agHelper.AddDsl("jsonFormDslWithoutSchema"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); cy.openFieldConfiguration("switch"); - }); - - it("2. has default property", () => { + // assert default property cy.get(".t--property-control-defaultselected").contains( "{{sourceData.switch}}", ); }); - it("3. should update field checked state when default selected changed", () => { + it("2. should update field checked state when default selected changed", () => { cy.testJsontext("defaultselected", "{{false}}"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-switch label.bp3-control.bp3-switch`).should( "have.class", "t--switch-widget-inactive", ); + entityExplorer.dra; + deployMode.NavigateBacktoEditor(); }); - it("4. hides field when visible switched off", () => { - cy.togglebarDisable(`.t--property-control-visible input`); + it("3. hides field when visible switched off", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("switch"); + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-switch`).should("not.exist"); - cy.wait(500); - cy.togglebar(`.t--property-control-visible input`); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("switch"); + propPane.TogglePropertyState("Visible", "On"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-switch`).should("exist"); + deployMode.NavigateBacktoEditor(); }); - it("5. disables field when disabled switched on", () => { - cy.togglebar(`.t--property-control-disabled input`); + it("4. disables field when disabled switched on", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("switch"); + propPane.TogglePropertyState("Disabled", "On"); + deployMode.DeployApp(); cy.get(`${fieldPrefix}-switch input`).each(($el) => { cy.wrap($el).should("have.attr", "disabled"); }); - cy.togglebarDisable(`.t--property-control-disabled input`); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("switch"); + propPane.TogglePropertyState("Disabled", "Off"); }); - it("6. Select Field Property Control - pre condition", () => { + it("5. Select Field Property Control - pre condition", () => { const schema = { state: "Karnataka", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); + agHelper.AddDsl("jsonFormDslWithoutSchema"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("state"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Select/); - }); - - it("7. has valid default value", () => { + // assert valid default value cy.get(".t--property-control-defaultselectedvalue").contains( "{{sourceData.state}}", ); }); - it("8. makes select filterable", () => { + it("6. makes select filterable", () => { // click select field and filter input should not exist cy.get(`${fieldPrefix}-state .bp3-control-group`).click({ force: true }); cy.get(`.bp3-select-popover .bp3-input-group`).should("not.exist"); @@ -90,75 +108,43 @@ describe("Text Field Property Control", () => { // toggle filterable -> true in property pane cy.togglebar(`.t--property-control-allowsearching input`); + deployMode.DeployApp(); + // click select field and filter input should exist cy.get(`${fieldPrefix}-state .bp3-control-group`).click({ force: true }); cy.get(`.bp3-select-popover .bp3-input-group`).should("exist"); + deployMode.NavigateBacktoEditor(); }); - it("9. hides field when visible switched off", () => { - cy.togglebarDisable(`.t--property-control-visible input`); - cy.get(`${fieldPrefix}-state`).should("not.exist"); - cy.wait(500); - cy.togglebar(`.t--property-control-visible input`); - cy.get(`${fieldPrefix}-state`).should("exist"); - }); - - it("10. disables field when disabled switched on", () => { - cy.togglebar(`.t--property-control-disabled input`); - cy.get(`${fieldPrefix}-state button.bp3-button`).should( - "have.class", - "bp3-disabled", - ); - - cy.togglebarDisable(`.t--property-control-disabled input`); - }); - - it("11. Multi Field Property Control - pre condition", () => { + it("7. Multi Field Property Control - pre condition", () => { const schema = { hobbies: [], }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); + agHelper.AddDsl("jsonFormDslWithoutSchema"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); cy.openFieldConfiguration("hobbies"); - }); - - it("12. has valid default value", () => { + // assert valid default value cy.get(".t--property-control-defaultselectedvalues").contains( "{{sourceData.hobbies}}", ); cy.closePropertyPane(); }); - it("13. adds placeholder text", () => { + it("8. adds placeholder text", () => { cy.openPropertyPane("jsonformwidget"); cy.openFieldConfiguration("hobbies"); cy.testJsontext("placeholder", "Select placeholder"); - cy.wait(2000); + deployMode.DeployApp(); cy.get(`.rc-select-selection-placeholder`).contains("Select placeholder"); + deployMode.NavigateBacktoEditor(); }); - it("14. hides field when visible switched off", () => { - cy.togglebarDisable(`.t--property-control-visible input`); - cy.get(`${fieldPrefix}-hobbies`).should("not.exist"); - cy.wait(500); - cy.togglebar(`.t--property-control-visible input`); - cy.get(`${fieldPrefix}-hobbies`).should("exist"); - }); - - it("15. disables field when disabled switched on", () => { - cy.togglebar(`.t--property-control-disabled input`); - cy.get(`${fieldPrefix}-hobbies .rc-select-multiple`).should( - "have.class", - "rc-select-disabled", - ); - - cy.togglebarDisable(`.t--property-control-disabled input`); - }); - - it("16. Invalid options should not crash the widget", () => { + it("9. Invalid options should not crash the widget", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.openFieldConfiguration("hobbies"); // clear Options cy.testJsonTextClearMultiline("options"); // enter invalid options @@ -180,27 +166,25 @@ describe("Text Field Property Control", () => { cy.get(`${fieldPrefix}-hobbies`).should("exist"); }); - it("17. Radio group Field Property Control - pre condition", () => { + it("10. Radio group Field Property Control - pre condition", () => { const sourceData = { radio: "Y", }; - _.agHelper.AddDsl("jsonFormDslWithoutSchema"); + agHelper.AddDsl("jsonFormDslWithoutSchema"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + cy.openFieldConfiguration("radio"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, "Radio Group"); - }); - - it("18. has valid default value", () => { + // assert valid default value cy.get(".t--property-control-defaultselectedvalue").contains( "{{sourceData.radio}}", ); cy.get(`${fieldPrefix}-radio input`).should("have.value", "Y"); - }); - it("19. hides field when visible switched off", () => { + // hides field when visible switched off" cy.togglebarDisable(`.t--property-control-visible input`); cy.get(`${fieldPrefix}-radio`).should("not.exist"); cy.wait(500); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FilterText_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FilterText_spec.js index 9f3716110c..7e2fbdf333 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FilterText_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FilterText_spec.js @@ -6,8 +6,14 @@ const dslWithoutSchema = require("../../../../../fixtures/jsonFormDslWithoutSche const commonlocators = require("../../../../../locators/commonlocators.json"); const onFilterUpdateJSBtn = ".t--property-control-onfilterupdate .t--js-toggle"; const fieldPrefix = ".t--jsonformfield"; +import { + deployMode, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; let agHelper = ObjectsRegistry.AggregateHelper; +let locators = ObjectsRegistry.CommonLocators; describe("JSONForm Select field - filterText update action trigger ", () => { beforeEach(() => { @@ -18,38 +24,37 @@ describe("JSONForm Select field - filterText update action trigger ", () => { agHelper.SaveLocalStorageCache(); }); - it("1. JSONForm Select field - filterText update action trigger - pre condition", () => { - const schema = { - color: "GREEN", - }; - cy.addDsl(dslWithoutSchema); - cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); - cy.openFieldConfiguration("color"); - cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Select$/); - cy.closePropertyPane(); - }); + before( + "JSONForm Select field - filterText update action trigger - pre condition", + () => { + const schema = { + color: "GREEN", + }; + cy.addDsl(dslWithoutSchema); + cy.openPropertyPane("jsonformwidget"); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("color"); + cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Select$/); + cy.closePropertyPane(); + }, + ); - it("2. shows alert on filter text change", () => { + it("1. shows alert on filter text change", () => { const filterText = "Test string"; cy.openPropertyPane("jsonformwidget"); cy.openFieldConfiguration("color"); // Enable filterable - cy.togglebar(`.t--property-control-allowsearching input`); - // Enable server side filtering - cy.togglebar(`.t--property-control-serversidefiltering input`); + propPane.TogglePropertyState("Allow searching", "On"); + propPane.TogglePropertyState("Server side filtering", "On"); - // Enable JS mode for onFilterUpdate - cy.get(onFilterUpdateJSBtn).click({ force: true }); - - // Add onFilterUpdate action - cy.testJsontext( - "onfilterupdate", + propPane.EnterJSContext( + "onFilterUpdate", "{{showAlert('Filter update:' + fieldState?.color?.filterText)}}", ); + deployMode.DeployApp(); // click select field and filter input should exist cy.get(`${fieldPrefix}-color .bp3-control-group`).click({ force: true }); cy.get(`.bp3-select-popover .bp3-input-group`).should("exist"); @@ -58,28 +63,25 @@ describe("JSONForm Select field - filterText update action trigger ", () => { cy.get(`.bp3-select-popover .bp3-input-group input`).type(filterText); cy.get(commonlocators.toastmsg).contains(`Filter update:${filterText}`); + deployMode.NavigateBacktoEditor(); }); - it("3. JSONForm Multiselect field - filterText update action trigger - pre condition", () => { + it("2. shows alert on filter text change", () => { + // JSONForm Multiselect field - filterText update action trigger - pre condition const schema = { colors: ["GREEN", "BLUE"], }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); - cy.closePropertyPane(); - }); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); - it("4. shows alert on filter text change", () => { const filterText = "Test string"; cy.openPropertyPane("jsonformwidget"); cy.openFieldConfiguration("colors"); - // Enable filterable - cy.togglebar(`.t--property-control-allowsearching input`); - // Enable server side filtering - cy.togglebar(`.t--property-control-serversidefiltering input`); + propPane.TogglePropertyState("Allow searching", "On"); + propPane.TogglePropertyState("Server side filtering", "On"); // Enable JS mode for onFilterUpdate cy.get(onFilterUpdateJSBtn).click({ force: true }); @@ -90,6 +92,7 @@ describe("JSONForm Select field - filterText update action trigger ", () => { "{{showAlert('Filter update:' + fieldState?.colors?.filterText)}}", ); + deployMode.DeployApp(); // Open multiselect field and filter input should exist cy.get(`${fieldPrefix}-colors`) .find(".rc-select-selection-search-input") diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Footer_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Footer_spec.js index c57c0523bd..4fd4b4457d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Footer_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Footer_spec.js @@ -16,7 +16,7 @@ describe("JSONForm Footer spec", () => { name: "John", }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); + _.propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); // check if fixed footer enabled cy.get(".t--property-control-fixedfooter") @@ -52,6 +52,7 @@ describe("JSONForm Footer spec", () => { _.agHelper.AddDsl("jsonFormDslWithSchema"); //Should not be needed, to check cy.openPropertyPane("jsonformwidget"); + cy.get(_.locators._jsToggle("sourcedata")).click({ force: true }); // check if fixed footer enabled cy.get(".t--property-control-fixedfooter") .find(".ads-v2-switch input") diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormBindings_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormBindings_spec.js index 999b2d739b..11710ec46b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormBindings_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormBindings_spec.js @@ -7,6 +7,7 @@ let backBtn = "[data-testid='t--property-pane-back-btn']"; import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; const agHelper = ObjectsRegistry.AggregateHelper; +const locators = ObjectsRegistry.CommonLocators; describe("JSON Form Widget Form Bindings", () => { afterEach(() => { @@ -16,6 +17,8 @@ describe("JSON Form Widget Form Bindings", () => { beforeEach(() => { agHelper.RestoreLocalStorageCache(); cy.addDsl(dslWithSchema); + cy.openPropertyPane("jsonformwidget"); + cy.get(locators._jsToggle("sourcedata")).click({ force: true }); }); it("1. updates formData when field value changes", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormProperties_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormProperties_spec.js index 53515cbb52..108ed07725 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormProperties_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_FormProperties_spec.js @@ -8,22 +8,25 @@ const fieldPrefix = ".t--jsonformfield"; const propertyControlPrefix = ".t--property-control"; const submitButtonStylesSection = ".t--property-pane-section-submitbuttonstyles"; -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + entityExplorer, + propPane, + locators, +} from "../../../../../support/Objects/ObjectsCore"; describe("JSON Form Widget Form Bindings", () => { beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); + agHelper.RestoreLocalStorageCache(); }); afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); - before(() => { + before("Add dsl and check fields under field configuration", () => { cy.addDsl(dslWithSchema); - }); - - it("1. should have all the fields under field configuration", () => { cy.openPropertyPane("jsonformwidget"); const fieldNames = [ "name", @@ -40,7 +43,7 @@ describe("JSON Form Widget Form Bindings", () => { }); }); - it("2. Field Configuration - adds new custom field", () => { + it("1. Field Configuration - adds new custom field", () => { cy.openPropertyPane("jsonformwidget"); // Add new field @@ -48,11 +51,16 @@ describe("JSON Form Widget Form Bindings", () => { force: true, }); + deployMode.DeployApp(); // Check for the presence of newly added custom field - cy.get(`[data-rbd-draggable-id='customField1']`).should("exist"); + cy.get(`.t--jsonformfield-customField1`).should("exist"); + + deployMode.NavigateBacktoEditor(); }); - it("3. Disabled Invalid Forms - disables the submit button when form has invalid field(s)", () => { + it("2. Disabled Invalid Forms - disables the submit button when form has invalid field(s)", () => { + entityExplorer.SelectEntityByName("JSONForm1"); + cy.get("button") .contains("Submit") .parent("button") @@ -60,9 +68,9 @@ describe("JSON Form Widget Form Bindings", () => { // make name field required cy.openFieldConfiguration("name"); - cy.togglebar(`${propertyControlPrefix}-required input`); + propPane.TogglePropertyState("Required", "On"); + deployMode.DeployApp(); - cy.get(backBtn).click({ force: true }); cy.get(`${fieldPrefix}-name input`).clear().wait(300); cy.get("button") .contains("Submit") @@ -75,36 +83,24 @@ describe("JSON Form Widget Form Bindings", () => { .contains("Submit") .parent("button") .should("not.have.attr", "disabled"); + deployMode.NavigateBacktoEditor(); }); - it("4. Should set isValid to false when form is invalid", () => { + it("3. Should set isValid to false when form is invalid", () => { + entityExplorer.SelectEntityByName("JSONForm1"); cy.openPropertyPane("textwidget"); cy.testJsontext("text", "{{JSONForm1.isValid}}"); - cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).contains("true"); - cy.get(`${fieldPrefix}-name input`).clear().wait(300); - cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).contains("false"); - cy.get(`${fieldPrefix}-name input`).type("JOHN").wait(300); - cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).contains("true"); }); - it("5. show show icon select when a collapsed section is opened", () => { + it("4. show show icon select when a collapsed section is opened", () => { cy.openPropertyPane("jsonformwidget"); cy.moveToStyleTab(); - // Check Submit Button Styles hidden - //cy.get(submitButtonStylesSection).should("not.be.visible"); - // .parent() - // .should("have.attr", "aria-hidden", "true"); - /* - // Open Submit Button Section - cy.get(".t--property-pane-section-collapse-submitbuttonstyles").click({ - force: true, - }); - */ + // Click Icon property cy.get(submitButtonStylesSection).contains("(none)").parent().click({ force: true, @@ -114,7 +110,7 @@ describe("JSON Form Widget Form Bindings", () => { cy.get(".bp3-select-popover .virtuoso-grid-item").should("be.visible"); }); - it("6. Should set isValid to false on first load when form is invalid", () => { + it("5. Should set isValid to false on first load when form is invalid", () => { cy.addDsl(dslWithoutSchema); const schema = { @@ -125,20 +121,20 @@ describe("JSON Form Widget Form Bindings", () => { cy.testJsontext("text", "{{JSONForm1.isValid}}"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); // make name field required cy.openFieldConfiguration("name"); cy.togglebar(`${propertyControlPrefix}-required input`); - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.get(".t--widget-textwidget .bp3-ui-text").contains("false"); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); - it("7. Should set isValid to false on reset when form is invalid", () => { + it("6. Should set isValid to false on reset when form is invalid", () => { cy.addDsl(dslWithoutSchema); const schema = { @@ -149,13 +145,13 @@ describe("JSON Form Widget Form Bindings", () => { cy.testJsontext("text", "{{JSONForm1.isValid}}"); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); // make name field required cy.openFieldConfiguration("name"); cy.togglebar(`${propertyControlPrefix}-required input`); - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.get(".t--widget-textwidget .bp3-ui-text").contains("false"); @@ -171,10 +167,10 @@ describe("JSON Form Widget Form Bindings", () => { cy.get("button").contains("Reset").click({ force: true }); cy.get(".t--widget-textwidget .bp3-ui-text").contains("false"); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); - it("8. Form value should contain hidden fields value if useSourceData is set to true", () => { + it("7. Form value should contain hidden fields value if useSourceData is set to true", () => { cy.addDsl(dslWithoutSchema); const schema = { @@ -183,7 +179,7 @@ describe("JSON Form Widget Form Bindings", () => { }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); cy.togglebar(`${propertyControlPrefix}-hiddenfieldsindata input`); @@ -198,7 +194,7 @@ describe("JSON Form Widget Form Bindings", () => { ); }); - it("9. Form value should not contain hidden fields value if useSourceData is set to false", () => { + it("8. Form value should not contain hidden fields value if useSourceData is set to false", () => { cy.addDsl(dslWithoutSchema); const name = "JOHN"; @@ -209,7 +205,7 @@ describe("JSON Form Widget Form Bindings", () => { }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); cy.togglebarDisable(`${propertyControlPrefix}-hiddenfieldsindata input`); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_1_spec.js index 794ac580ce..e1be0f1c94 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_1_spec.js @@ -6,6 +6,7 @@ import { entityExplorer, deployMode, propPane, + locators, } from "../../../../../support/Objects/ObjectsCore"; const fieldPrefix = ".t--jsonformfield"; @@ -85,6 +86,8 @@ function removeCustomField() { describe("JSON Form Hidden fields", () => { before(() => { agHelper.AddDsl("jsonFormDslWithSchema"); + cy.openPropertyPane("jsonformwidget"); + cy.get(locators._jsToggle("sourcedata")).click({ force: true }); entityExplorer.SelectEntityByName("Text1"); propPane.UpdatePropertyFieldValue( "Text", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_2_spec.js index 67fedc45c1..c51fdcdcac 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_HiddenFields_2_spec.js @@ -6,6 +6,7 @@ import { entityExplorer, deployMode, propPane, + locators, } from "../../../../../support/Objects/ObjectsCore"; const fieldPrefix = ".t--jsonformfield"; @@ -67,6 +68,9 @@ function changeFieldType(fieldName, fieldType) { function addCustomField(fieldType) { cy.openPropertyPane("jsonformwidget"); + cy.get(".t--property-control-sourcedata") + .find(".t--js-toggle") + .click({ force: true }); cy.backFromPropertyPanel(); // Add new field @@ -85,6 +89,8 @@ function removeCustomField() { describe("JSON Form Hidden fields", () => { before(() => { agHelper.AddDsl("jsonFormDslWithSchema"); + cy.openPropertyPane("jsonformwidget"); + cy.get(locators._jsToggle("sourcedata")).click({ force: true }); entityExplorer.SelectEntityByName("Text1"); propPane.UpdatePropertyFieldValue( "Text", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_MultipleSourceData_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_MultipleSourceData_spec.js index 4190560d6c..7be31fd6ff 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_MultipleSourceData_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_MultipleSourceData_spec.js @@ -16,7 +16,8 @@ describe("Verify syntax to create Datpicker field type", () => { const schema = { Key: "20/03/1992" }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + _.propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.xpath(jsonform.datepickerContainer).click({ force: true, }); @@ -27,7 +28,8 @@ describe("Verify syntax to create Datpicker field type", () => { const schema = { Key: true }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + _.propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.get(jsonform.switchStatus).should("be.visible"); cy.get(jsonform.switchStatus).click({ force: true }); }); @@ -36,7 +38,8 @@ describe("Verify syntax to create Datpicker field type", () => { const schema = { Key: "Value@mail.com" }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + _.propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.xpath(jsonform.emailField).should("be.visible"); cy.xpath(jsonform.emailField).should("have.value", "Value@mail.com"); }); @@ -45,7 +48,8 @@ describe("Verify syntax to create Datpicker field type", () => { const schema = { Key: "value" }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + _.propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.get(jsonform.keyInput).should("be.visible"); cy.get(jsonform.keyInput).should("have.value", "value"); }); @@ -58,7 +62,8 @@ describe("Verify syntax to create Datpicker field type", () => { }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + _.propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.get(jsonform.settings) .first() .should("be.visible") @@ -84,6 +89,7 @@ describe("Verify syntax to create Datpicker field type", () => { it("7. Verify property name change with json/text widget binding - Modify property name and check how the binding value changes", () => { cy.addDsl(jsonText); cy.openPropertyPane("jsonformwidget"); + cy.get(_.locators._jsToggle("sourcedata")).click({ force: true }); cy.get(jsonform.settings) .first() .should("be.visible") diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_NestedField_Select_Multiselect.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_NestedField_Select_Multiselect.js index 47d7b5b004..303fb7e8e0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_NestedField_Select_Multiselect.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_NestedField_Select_Multiselect.js @@ -8,6 +8,8 @@ const dslWithoutSchema = require("../../../../../fixtures/jsonFormDslWithoutSche const fieldPrefix = ".t--jsonformfield"; import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; let agHelper = ObjectsRegistry.AggregateHelper; +let locators = ObjectsRegistry.CommonLocators; +let propPane = ObjectsRegistry.PropertyPane; describe("JSONForm select field", () => { beforeEach(() => { @@ -31,7 +33,8 @@ describe("JSONForm select field", () => { }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("object"); cy.openFieldConfiguration("select", false); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Select$/); @@ -91,7 +94,8 @@ describe("JSONForm select field", () => { }; cy.addDsl(dslWithoutSchema); cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("object"); cy.openFieldConfiguration("multiselect", false); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Multiselect$/); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_RadioGroupField_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_RadioGroupField_spec.js index 1ec45f3d1f..c4c8ca6669 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_RadioGroupField_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_RadioGroupField_spec.js @@ -3,6 +3,8 @@ const dslWithoutSchema = require("../../../../../fixtures/jsonFormDslWithoutSche const fieldPrefix = ".t--jsonformfield"; import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; let agHelper = ObjectsRegistry.AggregateHelper; +let locators = ObjectsRegistry.CommonLocators; +let propPane = ObjectsRegistry.PropertyPane; function selectAndValidateOption(selector, option, expectedFormData) { // Select option Zero @@ -68,7 +70,8 @@ describe("JSONForm RadioGroup Field", () => { // Apply schema and change the field type to radio group cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("binary"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Radio Group$/); @@ -117,7 +120,8 @@ describe("JSONForm RadioGroup Field", () => { // Apply schema and change the field type to radio group cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(schema)); + propPane.EnterJSContext("Source data", JSON.stringify(schema), true); + cy.openFieldConfiguration("accept"); cy.selectDropdownValue(commonlocators.jsonFormFieldType, /^Radio Group$/); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Reset_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Reset_spec.js index 635b14a0d5..7beb72e976 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Reset_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Reset_spec.js @@ -1,10 +1,13 @@ const dslWithSchema = require("../../../../../fixtures/jsonFormDslWithSchema.json"); - +import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; +const locators = ObjectsRegistry.CommonLocators; const fieldPrefix = ".t--jsonformfield"; describe("JSON Form reset", () => { before(() => { cy.addDsl(dslWithSchema); + cy.openPropertyPane("jsonformwidget"); + cy.get(locators._jsToggle("sourcedata")).click({ force: true }); }); it("updates formData when field value changes", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_UnicodeKeys_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_UnicodeKeys_spec.js index 89bc03123c..80f5b36fbf 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_UnicodeKeys_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_UnicodeKeys_spec.js @@ -3,6 +3,8 @@ const jsonFormUnicodeDSLWithoutSourceData = require("../../../../../fixtures/jso const widgetsPage = require("../../../../../locators/Widgets.json"); import { ObjectsRegistry } from "../../../../../support/Objects/Registry"; const agHelper = ObjectsRegistry.AggregateHelper; +const locators = ObjectsRegistry.CommonLocators; +const propPane = ObjectsRegistry.PropertyPane; const fieldPrefix = ".t--jsonformfield"; const backBtn = "[data-testid='t--property-pane-back-btn']"; @@ -31,7 +33,8 @@ describe("JSON Form Widget Unicode keys", () => { }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + cy.closePropertyPane(); cy.get(`${fieldPrefix}-xn__l2bm1c label`).contains("नाम"); @@ -85,7 +88,12 @@ describe("JSON Form Widget Unicode keys", () => { }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(modifiedSourceData)); + propPane.EnterJSContext( + "Source data", + JSON.stringify(modifiedSourceData), + true, + ); + cy.closePropertyPane(); cy.get(`${fieldPrefix}-xn____xvdesr5bxbc label`).contains("पहला नाम"); @@ -152,7 +160,8 @@ describe("JSON Form Widget Unicode keys", () => { }; cy.openPropertyPane("jsonformwidget"); - cy.testJsontext("sourcedata", JSON.stringify(sourceData)); + propPane.EnterJSContext("Source data", JSON.stringify(sourceData), true); + cy.closePropertyPane(); const expectedInitialFormData = sourceData; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/List/List4_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/List/List4_2_spec.js index 74b79e33b8..f84361e977 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/List/List4_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/List/List4_2_spec.js @@ -103,17 +103,11 @@ describe("Container Widget Functionality", function () { }); it("6. Renaming the widget from Property pane and Entity explorer ", function () { - // Open Property pane - _.entityExplorer.SelectEntityByName("List1", "Widgets"); - - // Change the list widget name from property pane and Verify it - cy.widgetText( - "List2", - widgetsPage.listWidgetName, - widgetsPage.widgetNameSpan, - ); + // Open Property pane & rename the list widget + _.propPane.RenameWidget("List1", "List2"); + _.agHelper.Sleep(); //for renaming the widget // Change the list widget name from Entity Explorer - cy.renameEntity("List2", "List1"); + _.entityExplorer.RenameEntityFromExplorer("List2", "List1", false); // Mouse over to list name _.entityExplorer.SelectEntityByName("List1"); @@ -126,6 +120,5 @@ describe("Container Widget Functionality", function () { "List1", ); _.deployMode.DeployApp(); - _.deployMode.NavigateBacktoEditor(); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/DataIdentifierProperty_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/DataIdentifierProperty_spec.ts index ec5f398030..dd6109df4c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/DataIdentifierProperty_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/DataIdentifierProperty_spec.ts @@ -5,31 +5,9 @@ import { propPane, draggableWidgets, debuggerHelper, - apiPage, table, } from "../../../../../support/Objects/ObjectsCore"; -const data = [ - { - id: "001", - name: "Blue", - img: "https://assets.appsmith.com/widgets/default.png", - same: "1", - }, - { - id: "002", - name: "Green", - img: "https://assets.appsmith.com/widgets/default.png", - same: "01", - }, - { - id: "003", - name: "Red", - img: "https://assets.appsmith.com/widgets/default.png", - same: 1, - }, -]; - describe("List v2 - Data Identifier property", () => { beforeEach(() => { agHelper.RestoreLocalStorageCache(); @@ -118,57 +96,4 @@ describe("List v2 - Data Identifier property", () => { "This data identifier is evaluating to a duplicate value. Please use an identifier that evaluates to a unique value.", ); }); - - it("7. Widgets get displayed when PrimaryKey doesn't exist - SSP", () => { - agHelper.AddDsl("Listv2/ListV2WithNullPrimaryKey"); - apiPage.CreateAndFillApi( - "https://api.punkapi.com/v2/beers?page={{List1.pageNo}}&per_page={{List1.pageSize}}", - "", - ); - agHelper.VerifyEvaluatedValue( - "https://api.punkapi.com/v2/beers?page=1&per_page=2", - ); - apiPage.RunAPI(false); - entityExplorer.ExpandCollapseEntity("List1"); - entityExplorer.SelectEntityByName("Text2", "Container1"); - propPane.UpdatePropertyFieldValue("Text", "{{currentIndex}}"); - agHelper.AssertText(propPane._widgetToVerifyText("Text2"), "text", "0"); - table.NavigateToPageUsingButton_List("next", 2); - agHelper.AssertText(propPane._widgetToVerifyText("Text2"), "text", "0"); - }); - - it("8. Widgets get displayed when PrimaryKey doesn't exist - Client-Side Pagination", () => { - entityExplorer.ExpandCollapseEntity("List2"); - entityExplorer.SelectEntityByName("Text4", "Container2"); - propPane.UpdatePropertyFieldValue("Text", "{{currentIndex}}"); - agHelper.AssertText(propPane._widgetToVerifyText("Text4"), "text", "0"); - - table.NavigateToNextPage_List("v2", 1); - agHelper.AssertText(propPane._widgetToVerifyText("Text4"), "text", "1"); - - table.NavigateToNextPage_List("v2", 1); - agHelper.AssertText(propPane._widgetToVerifyText("Text4"), "text", "2"); - }); - - it("9. Non unique data identifier should throw error- (data type issue)", () => { - entityExplorer.SelectEntityByName("List2"); - propPane.UpdatePropertyFieldValue("Items", JSON.stringify(data)); - // clicking on the data identifier dropdown - propPane.RemoveText("dataidentifier"); - propPane.ToggleJSMode("Data Identifier", false); - // clicking on the data identifier dropdown and select key same - propPane.SelectPropertiesDropDown("Data Identifier", "same"); - agHelper.AssertElementLength( - `${locators._widgetByName("List2")} ${locators._widgetInCanvas( - draggableWidgets.CONTAINER, - )}`, - 1, - ); - //Open debugger by clicking debugger icon in canvas. - debuggerHelper.ClickDebuggerIcon(); - agHelper.GetNAssertContains( - debuggerHelper.locators._debuggerList, - "This data identifier is evaluating to a duplicate value. Please use an identifier that evaluates to a unique value.", - ); - }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/DataIdentifier_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/DataIdentifier_spec.ts new file mode 100644 index 0000000000..024b4a58ad --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/DataIdentifier_spec.ts @@ -0,0 +1,90 @@ +import { + agHelper, + locators, + entityExplorer, + propPane, + draggableWidgets, + debuggerHelper, + apiPage, + table, +} from "../../../../../support/Objects/ObjectsCore"; + +const data = [ + { + id: "001", + name: "Blue", + img: "https://assets.appsmith.com/widgets/default.png", + same: "1", + }, + { + id: "002", + name: "Green", + img: "https://assets.appsmith.com/widgets/default.png", + same: "01", + }, + { + id: "003", + name: "Red", + img: "https://assets.appsmith.com/widgets/default.png", + same: 1, + }, +]; + +describe("List v2 - Data Identifier property", () => { + before(() => { + agHelper.AddDsl("Listv2/ListV2WithNullPrimaryKey"); + agHelper.Sleep(3000); //for List to load for CI flakyness + }); + + it("1. Widgets get displayed when PrimaryKey doesn't exist - SSP", () => { + apiPage.CreateAndFillApi( + "https://api.punkapi.com/v2/beers?page={{List1.pageNo}}&per_page={{List1.pageSize}}", + "", + ); + agHelper.VerifyEvaluatedValue( + "https://api.punkapi.com/v2/beers?page=1&per_page=2", + ); + apiPage.RunAPI(false); + entityExplorer.ExpandCollapseEntity("List1"); + entityExplorer.SelectEntityByName("Text2", "Container1"); + propPane.UpdatePropertyFieldValue("Text", "{{currentIndex}}"); + agHelper.AssertText(propPane._widgetToVerifyText("Text2"), "text", "0"); + table.NavigateToPageUsingButton_List("next", 2); + agHelper.AssertText(propPane._widgetToVerifyText("Text2"), "text", "0"); + }); + + it("2. Widgets get displayed when PrimaryKey doesn't exist - Client-Side Pagination", () => { + entityExplorer.ExpandCollapseEntity("List2"); + entityExplorer.SelectEntityByName("Text4", "Container2"); + propPane.UpdatePropertyFieldValue("Text", "{{currentIndex}}"); + agHelper.AssertText(propPane._widgetToVerifyText("Text4"), "text", "0"); + + table.NavigateToNextPage_List("v2", 1); + agHelper.AssertText(propPane._widgetToVerifyText("Text4"), "text", "1"); + + table.NavigateToNextPage_List("v2", 1); + agHelper.AssertText(propPane._widgetToVerifyText("Text4"), "text", "2"); + }); + + it("3. Non unique data identifier should throw error- (data type issue)", () => { + entityExplorer.SelectEntityByName("List2"); + propPane.UpdatePropertyFieldValue("Items", JSON.stringify(data)); + // clicking on the data identifier dropdown + propPane.RemoveText("dataidentifier"); + propPane.ToggleJSMode("Data Identifier", false); + // clicking on the data identifier dropdown and select key same + propPane.SelectPropertiesDropDown("Data Identifier", "same"); + agHelper.AssertElementLength( + `${locators._widgetByName("List2")} ${locators._widgetInCanvas( + draggableWidgets.CONTAINER, + )}`, + 1, + ); + //Open debugger by clicking debugger icon in canvas. + debuggerHelper.ClickDebuggerIcon(); + agHelper.GetNAssertContains( + debuggerHelper.locators._debuggerList, + "This data identifier is evaluating to a duplicate value. Please use an identifier that evaluates to a unique value.", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_NestedList_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_NestedList_spec.ts new file mode 100644 index 0000000000..5b0d9269cf --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_NestedList_spec.ts @@ -0,0 +1,146 @@ +import { WIDGET } from "../../../../../locators/WidgetLocators"; +import { + agHelper, + entityExplorer, + deployMode, + propPane, + appSettings, + locators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Nested List widget V2 ", () => { + before(() => { + agHelper.AddDsl("listV2NestedDsl"); + }); + + it("1. Verify only 3 levels of nesting is allowed", () => { + agHelper.AssertContains( + "Oops, Something went wrong.", + "not.exist", + locators._widgetInCanvas(WIDGET.LIST_V2), + ); + agHelper + .GetElement(locators._widgetInCanvas(WIDGET.LIST_V2)) + .should("have.length", 5); + entityExplorer.SelectEntityByName("List1", "Widgets"); + entityExplorer.SelectEntityByName("Container1", "List1"); + entityExplorer.SelectEntityByName("List2", "Container1"); + entityExplorer.SelectEntityByName("Container2", "List2"); + entityExplorer.SelectEntityByName("List3", "Container2"); + agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{c}`); + agHelper.Sleep(1000); + agHelper.WaitUntilAllToastsDisappear(); + entityExplorer.SelectEntityByName("Container3", "List3"); + agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{v}`); + agHelper.ValidateToastMessage( + "Cannot have more than 3 levels of nesting in the list widget", + ); + }); + + it("2. Verify nested List has same property as parent", () => { + const dataProperties = ["items", "dataidentifier"]; + + const paginationProperties = ["serversidepagination"]; + + const itemSelectionProperties = ["defaultselecteditem", "onitemclick"]; + + const generalProperties = ["visible", "animateloading"]; + + // Parent List + entityExplorer.SelectEntityByName("List1", "Widgets"); + propPane.AssertPropertyVisibility(dataProperties, "data"); + propPane.AssertPropertyVisibility(paginationProperties, "pagination"); + propPane.AssertPropertyVisibility(itemSelectionProperties, "itemselection"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + + // First Child, List2 + entityExplorer.SelectEntityByName("List2", "Widgets"); + propPane.AssertPropertyVisibility(dataProperties, "data"); + propPane.AssertPropertyVisibility(paginationProperties, "pagination"); + propPane.AssertPropertyVisibility(itemSelectionProperties, "itemselection"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + + // Second Child, List3 + entityExplorer.SelectEntityByName("List3", "Widgets"); + propPane.AssertPropertyVisibility(dataProperties, "data"); + propPane.AssertPropertyVisibility(paginationProperties, "pagination"); + propPane.AssertPropertyVisibility(itemSelectionProperties, "itemselection"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + }); + + it("3. Verify auto suggestions and {{currentView}} displays all widgets added in that List ", () => { + // Verify level_1 and level_2 are available + entityExplorer.SelectEntityByName("Text5", "Container3"); + propPane.TypeTextIntoField("Text", "{{level"); + agHelper.Sleep(500); + agHelper.GetNAssertElementText( + locators._hintsList, + "level_1", + "contain.text", + ); + agHelper.GetNAssertElementText( + locators._hintsList, + "level_2", + "contain.text", + ); + + propPane.TypeTextIntoField("Text", "{{level1.currentView."); + agHelper.Sleep(500); + agHelper.GetNAssertElementText( + locators._hintsList, + "Image1", + "contain.text", + ); + agHelper.GetNAssertElementText( + locators._hintsList, + "Text1", + "contain.text", + ); + agHelper.GetNAssertElementText( + locators._hintsList, + "Text2", + "contain.text", + ); + agHelper.GetNAssertElementText( + locators._hintsList, + "List2", + "contain.text", + ); + + propPane.UpdatePropertyFieldValue( + "Text", + "{{level_1.currentView.Text1.text}}", + ); + agHelper.AssertText( + `${locators._widgetInDeployed("text5")} .bp3-ui-text`, + "text", + "Blue", + ); + }); + + it("4. Verify making child widget invisble should not break the app", () => { + entityExplorer.SelectEntityByName("List1", "Widgets"); + entityExplorer.SelectEntityByName("Container1", "List1"); + entityExplorer.SelectEntityByName("List2", "Container1"); + entityExplorer.SelectEntityByName("Container2", "List2"); + entityExplorer.SelectEntityByName("List3", "Container2"); + + propPane.TogglePropertyState("visible", "Off"); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._widgetInDeployed("list3")); + deployMode.NavigateBacktoEditor(); + }); + + it("5. Verify Theme change", () => { + agHelper.PressEscape(); + appSettings.OpenPaneAndChangeTheme("Pacific"); + [0, 1, 2].forEach((index) => { + agHelper.AssertAttribute( + locators._listText, + "font-family", + "Open Sans", + index, + ); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js index aa74bcc26d..b0376ffe89 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js @@ -46,11 +46,16 @@ describe("List widget V2 Serverside Pagination", () => { it("2. Next button disabled but visible in view mode when there's no data", () => { agHelper.AssertText(commonlocators.listPaginateActivePage, "text", "1"); agHelper.GetNClick(commonlocators.listPaginateNextButton, 0, true); + cy.wait(1000); agHelper.AssertText(commonlocators.listPaginateActivePage, "text", "2"); + cy.wait(1000); agHelper.GetNClick(commonlocators.listPaginateNextButton, 0, true); + cy.wait(1000); agHelper.AssertText(commonlocators.listPaginateActivePage, "text", "3"); agHelper.AssertElementExist(commonlocators.listPaginateNextButtonDisabled); + agHelper.GetNClick(commonlocators.listPaginatePrevButton, 0, true); + cy.wait(1000); agHelper.AssertText(commonlocators.listPaginateActivePage, "text", "2"); deployMode.NavigateBacktoEditor(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_WithOtherWidget_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_WithOtherWidget_spec.ts new file mode 100644 index 0000000000..53bb19eb1b --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_WithOtherWidget_spec.ts @@ -0,0 +1,106 @@ +import { + agHelper, + locators, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("List widget V2 functionality with audio and video widgets", () => { + before(() => { + agHelper.AddDsl("listV2AudioVideoDsl"); + entityExplorer.DragDropWidgetNVerify("audiowidget", 700, 500); + entityExplorer.DragDropWidgetNVerify("audiorecorderwidget", 700, 600); + entityExplorer.DragDropWidgetNVerify("videowidget", 400, 700); + entityExplorer.DragDropWidgetNVerify("textwidget", 700, 700); + }); + + after(() => { + agHelper.SelectAllWidgets(); + agHelper.PressDelete(); + }); + + it("1. Verify property visibility", () => { + const dataProperties = ["url"]; + + const generalProperties = ["autoplay", "visible", "animateloading"]; + + const eventsProperties = ["onplay", "onpause", "onend"]; + + const audioRecorderGeneralProperties = [ + "visible", + "disabled", + "animateloading", + ]; + + const audioRecorderEventsProperties = [ + "onrecordingstart", + "onrecordingcomplete", + ]; + + entityExplorer.SelectEntityByName("Audio2", "Widgets"); + // Audio widget outside List + propPane.AssertPropertyVisibility(dataProperties, "data"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + propPane.AssertPropertyVisibility(eventsProperties, "events"); + + // Audio widget inside List + entityExplorer.SelectEntityByName("List1", "Widgets"); + entityExplorer.SelectEntityByName("Container1", "List1"); + entityExplorer.SelectEntityByName("Audio1", "Container1"); + propPane.AssertPropertyVisibility(dataProperties, "data"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + propPane.AssertPropertyVisibility(eventsProperties, "events"); + + // Audio recorder widget outside List + entityExplorer.SelectEntityByName("AudioRecorder2", "Widgets"); + propPane.AssertPropertyVisibility( + audioRecorderGeneralProperties, + "general", + ); + propPane.AssertPropertyVisibility(audioRecorderEventsProperties, "events"); + + // Audio recorder widget inside List + entityExplorer.SelectEntityByName("AudioRecorder1", "Widgets"); + propPane.AssertPropertyVisibility( + audioRecorderGeneralProperties, + "general", + ); + propPane.AssertPropertyVisibility(audioRecorderEventsProperties, "events"); + + // Video widget outside List + entityExplorer.SelectEntityByName("Video2", "Widgets"); + propPane.AssertPropertyVisibility(dataProperties, "data"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + propPane.AssertPropertyVisibility(eventsProperties, "events"); + + // Video widget inside List + entityExplorer.SelectEntityByName("Video1", "Widgets"); + propPane.AssertPropertyVisibility(dataProperties, "data"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + propPane.AssertPropertyVisibility(eventsProperties, "events"); + }); + + it("2. Verify auto play", function () { + entityExplorer.SelectEntityByName("Audio1", "Widgets"); + propPane.TogglePropertyState("autoplay", "On"); + agHelper.AssertAttribute("audio", "autoplay", "autoplay"); + + entityExplorer.SelectEntityByName("Video1", "Widgets"); + propPane.TogglePropertyState("autoplay", "On"); + agHelper.AssertAttribute("video", "autoplay", "autoplay"); + }); + + it("3. Verify Binding", function () { + entityExplorer.SelectEntityByName("Text3", "Widgets"); + propPane.UpdatePropertyFieldValue("Text", "{{Audio1.autoPlay}}"); + agHelper.AssertText(locators._textWidgetStyleInDeployed, "text", "true", 2); + entityExplorer.SelectEntityByName("Audio1", "Widgets"); + propPane.TogglePropertyState("autoplay", "Off"); + agHelper.AssertText( + locators._textWidgetStyleInDeployed, + "text", + "false", + 2, + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_WithButtonGroupIconWidget_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_WithButtonGroupIconWidget_spec.ts new file mode 100644 index 0000000000..c4377b9c03 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_WithButtonGroupIconWidget_spec.ts @@ -0,0 +1,134 @@ +import { + agHelper, + locators, + entityExplorer, + draggableWidgets, + deployMode, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("List widget V2 functionality with button, button group and icon button widgets", () => { + before(() => { + agHelper.AddDsl("listV2ButtonsDsl", locators._buttonByText("Submit")); + entityExplorer.DragDropWidgetNVerify("buttonwidget", 500, 500); + entityExplorer.DragDropWidgetNVerify("buttongroupwidget", 500, 600); + entityExplorer.DragDropWidgetNVerify("iconbuttonwidget", 500, 700); + }); + + it("1. Verify property visibility", () => { + const basicProperties = ["label", "onclick"]; + + const generalProperties1 = ["visible", "disabled", "animateloading"]; + + const formSettingsProperties = [ + "disabledinvalidforms", + "resetformonsuccess", + ]; + + const buttonGroupDataProperties = ["buttons"]; + + const buttonGroupGeneralProperties = [ + "visible", + "disabled", + "animateloading", + ]; + + const iconButtonbasicProperties = ["icon", "onclick"]; + + // Button widget outside List + entityExplorer.SelectEntityByName("Button2", "Widgets"); + propPane.AssertPropertyVisibility(basicProperties, "basic"); + propPane.AssertPropertyVisibility(generalProperties1, "general"); + propPane.AssertPropertyVisibility(formSettingsProperties, "formsettings"); + + // Button widget inside List + entityExplorer.SelectEntityByName("List1", "Widgets"); + entityExplorer.SelectEntityByName("Container1", "List1"); + entityExplorer.SelectEntityByName("Button1", "Container1"); + propPane.AssertPropertyVisibility(basicProperties, "basic"); + propPane.AssertPropertyVisibility(generalProperties1, "general"); + propPane.AssertPropertyVisibility(formSettingsProperties, "formsettings"); + + entityExplorer.SelectEntityByName("ButtonGroup2", "Widgets"); + // Button group widget outside List + propPane.AssertPropertyVisibility(buttonGroupDataProperties, "data"); + propPane.AssertPropertyVisibility(buttonGroupGeneralProperties, "general"); + + // Button group widget inside List + entityExplorer.SelectEntityByName("ButtonGroup1", "Widgets"); + propPane.AssertPropertyVisibility(buttonGroupDataProperties, "data"); + propPane.AssertPropertyVisibility(buttonGroupGeneralProperties, "general"); + + // Icon Button widget outside List + entityExplorer.SelectEntityByName("IconButton2", "Widgets"); + propPane.AssertPropertyVisibility(iconButtonbasicProperties, "basic"); + propPane.AssertPropertyVisibility(buttonGroupGeneralProperties, "general"); + + // Icon Button widget inside List + entityExplorer.SelectEntityByName("IconButton1", "Widgets"); + propPane.AssertPropertyVisibility(iconButtonbasicProperties, "basic"); + propPane.AssertPropertyVisibility(buttonGroupGeneralProperties, "general"); + }); + + it("2. Verify onClick functionality", () => { + // Button + entityExplorer.SelectEntityByName("Button1", "Widgets"); + propPane.SelectPlatformFunction("onClick", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Button Clicked", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + agHelper.GetNClick(locators._widgetInDeployed("buttonwidget")); + agHelper.ValidateToastMessage("Button Clicked"); + + // Icon Button + entityExplorer.SelectEntityByName("IconButton1", "Widgets"); + propPane.SelectPlatformFunction("onClick", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Icon Button Clicked", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + agHelper.GetNClick(locators._widgetInDeployed("iconbuttonwidget")); + agHelper.ValidateToastMessage("Icon Button Clicked"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.GetNClick(locators._widgetInDeployed("buttonwidget")); + agHelper.WaitUntilToastDisappear("Button Clicked"); + agHelper.GetNClick(locators._widgetInDeployed("iconbuttonwidget")); + agHelper.ValidateToastMessage("Icon Button Clicked"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.GetNClick(locators._widgetInDeployed("buttonwidget")); + agHelper.WaitUntilToastDisappear("Button Clicked"); + agHelper.GetNClick(locators._widgetInDeployed("iconbuttonwidget")); + agHelper.ValidateToastMessage("Icon Button Clicked"); + deployMode.NavigateBacktoEditor(); + }); + + it("3. Verify Styles should be configured individually", () => { + entityExplorer.SelectEntityByName("List1", "Widgets"); + entityExplorer.SelectEntityByName("Container1", "List1"); + entityExplorer.SelectEntityByName("Button1", "Container1"); + propPane.MoveToTab("Style"); + agHelper.AssertAttribute("[data-value='PRIMARY']", "data-selected", "true"); + agHelper.GetNClick("[data-value='SECONDARY']"); + agHelper.AssertAttribute( + "[data-value='PRIMARY']", + "data-selected", + "false", + ); + + entityExplorer.SelectEntityByName("IconButton1", "Widgets"); + propPane.MoveToTab("Style"); + agHelper.AssertAttribute("[data-value='PRIMARY']", "data-selected", "true"); + + entityExplorer.SelectEntityByName("ButtonGroup1", "Widgets"); + propPane.MoveToTab("Style"); + agHelper.AssertAttribute("[data-value='PRIMARY']", "data-selected", "true"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Modal/Modal_Widget_With_Button_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Modal/Modal_Widget_With_Button_spec.ts index 2bc34d568b..500e52dc55 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Modal/Modal_Widget_With_Button_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Modal/Modal_Widget_With_Button_spec.ts @@ -14,7 +14,7 @@ describe("Modal Widget with auto-layout usecases", function () { _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.INPUT_V2, 10, 20); _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.BUTTON, 20, 30); _.agHelper.AssertElementAbsence(_.locators._modal); - _.propPane.CreateModal("Modal1", "onClick"); + _.propPane.CreateModal("onClick"); _.agHelper.GetNClick(_.locators._closeModal, 0, true, 0); _.agHelper.AssertElementExist(_.locators._widgetInCanvas("inputwidgetv2")); _.agHelper.AssertElementExist( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Modal/Modal_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Modal/Modal_spec.ts new file mode 100644 index 0000000000..d6dd991ffb --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Modal/Modal_spec.ts @@ -0,0 +1,371 @@ +import { + agHelper, + assertHelper, + deployMode, + draggableWidgets, + entityExplorer, + homePage, + locators, + propPane, + table, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Modal Widget test cases", function () { + const image = (src: string) => 'img[src="' + src + '"]'; + const jpgImg = "https://jpeg.org/images/jpegsystems-home.jpg"; + const gifImg = + "https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/5eeea355389655.59822ff824b72.gif"; + + it("1. Modal widget functionality", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MODAL, 300, 300); + entityExplorer.SelectEntityByName("Button1"); + propPane.EnterJSContext("onClick", "{{showModal('Modal1');}}"); + agHelper.Sleep(); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.BUTTON)); + agHelper.Sleep(2000); //Wait for widgets to settle + + //Verify that the Modal widget opens correctly when configured on a button click. + agHelper.ClickButton("Submit"); + agHelper.AssertElementVisibility(locators._modal); + + //Verify that the Modal widget is closed and no longer visible on the screen on clicking the "X" button. + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.ICONBUTTON), + ); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.ICONBUTTON)); + agHelper.AssertElementAbsence(locators._modal); + + //Verify that clicking outside the Modal widget closes it as expected when Quick dismiss is enabled + agHelper.ClickButton("Submit"); + agHelper.AssertElementVisibility(locators._modal); + agHelper.ClickOutside(350, 150, false); + agHelper.Sleep(); + agHelper.AssertElementAbsence(locators._modal); + }); + + it("2. Verify that multiple Modal widgets can be opened simultaneously.", () => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Button1"); + propPane.ToggleJSMode("onClick", false); + propPane.CreateModal("onClick"); + agHelper.Sleep(500); + propPane.CreateModal("onClick"); + agHelper.Sleep(500); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.BUTTON)); + agHelper.Sleep(2000); //Wait for widgets to settle & be visible + agHelper.ClickButton("Submit"); + agHelper.AssertElementLength(locators._modal, 3); + agHelper.AssertElementVisibility(locators._modal, true, 2); + agHelper.GetNClick( + locators._widgetInDeployed(draggableWidgets.ICONBUTTON), + 2, + ); + agHelper.AssertElementVisibility(locators._modal, true, 1); + agHelper.GetNClick( + locators._widgetInDeployed(draggableWidgets.ICONBUTTON), + 1, + ); + agHelper.AssertElementVisibility(locators._modal); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.ICONBUTTON)); + agHelper.AssertElementAbsence(locators._modal); + }); + + it("3. Verify that scroll appears when there are multiple widgets in modal", () => { + agHelper.ClickButton("Submit"); + agHelper.AssertProperty(locators._modal, "scrollTop", 0); + deployMode.NavigateBacktoEditor(); + homePage.NavigateToHome(); + + //Contains modal with couple of widgets(image, text, select, input, table, container, icon button, json form , list, tab) + homePage.ImportApp("modalWidgetTestApp.json"); + entityExplorer.SelectEntityByName("Modal1", "Widgets"); + + //Auto height + propPane.AssertPropertiesDropDownValues("Height", ["Auto Height", "Fixed"]); + propPane.AssertPropertiesDropDownCurrentValue("Height", "Auto Height"); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.BUTTON)); + + agHelper.ClickButton("Submit"); + agHelper.AssertElementVisibility(locators._modal); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.IMAGE), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.LIST_V2), + ); + agHelper + .GetElement(locators._modal) + .invoke("scrollTop") + .should("be.greaterThan", 400); + agHelper.ScrollTo(locators._modal, "bottom"); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.TABLE), + ); + + deployMode.NavigateBacktoEditor(); + + //Fixed height + entityExplorer.SelectEntityByName("Modal1", "Widgets"); + propPane.SelectPropertiesDropDown("Height", "Fixed"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.BUTTON)); + agHelper.ClickButton("Submit"); + agHelper.AssertElementVisibility(locators._modal); + + //Verify that a fixed canvas size is visible when height is selected as Fixed + agHelper.AssertProperty(locators._modal, "offsetHeight", 1094); + agHelper.AssertProperty(locators._modal, "offsetWidth", 456); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.IMAGE), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.LIST_V2), + ); + agHelper + .GetElement(locators._modal) + .invoke("scrollTop") + .should("be.greaterThan", 400); + agHelper.ScrollTo(locators._modal, "bottom"); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.TABLE), + ); + }); + + it("4. Verify that multiple widgets within the Modal widget can communicate without errors.", () => { + agHelper.ScrollTo(locators._modal, "top"); + + //Assert all the widgets in modal are visible + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.INPUT_V2), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.SELECT), + ); + agHelper.AssertElementVisibility( + locators._modal + " " + locators._widgetInDeployed(draggableWidgets.TEXT), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.IMAGE), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.LIST_V2), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.JSONFORM), + ); + + //Verify that complex layouts with nested widgets are displayed correctly within the Modal widget. + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.CONTAINER), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.CONTAINER) + + " " + + locators._widgetInDeployed(draggableWidgets.ICONBUTTON), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.CONTAINER) + + " " + + locators._widgetInDeployed(draggableWidgets.TAB), + ); + agHelper.AssertElementVisibility( + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.CONTAINER) + + " " + + locators._widgetInDeployed(draggableWidgets.TAB) + + " " + + locators._widgetInDeployed(draggableWidgets.TABLE), + ); + + //Input + agHelper.TypeText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "test", + ); + + //Validate input widget binding to select dropdown + agHelper.SelectDropDown("test1"); + agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + expect($selectedValue).to.eq("test1"); + }); + agHelper.SelectDropDown("test2"); + agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + expect($selectedValue).to.eq("test2"); + }); + + //Image + agHelper.AssertElementExist(image(gifImg)); + + //List + agHelper.AssertElementExist(image(jpgImg)); + agHelper.AssertElementLength(image(jpgImg), 3); + agHelper.GetNAssertContains( + locators._widgetInDeployed(draggableWidgets.TEXT), + "Blue", + ); + agHelper.GetNAssertContains( + locators._widgetInDeployed(draggableWidgets.TEXT), + "Green", + ); + agHelper.GetNAssertContains( + locators._widgetInDeployed(draggableWidgets.TEXT), + "Red", + ); + + //JSON Form + agHelper.TypeText(locators._jsonFormInputField("name"), "test user"); + agHelper.TypeText( + locators._jsonFormInputField("date_of_birth"), + "12/03/1999", + ); + agHelper.TypeText(locators._jsonFormInputField("employee_id"), "1234"); + agHelper.ClickButton("Submit", 1); + agHelper.ValidateToastMessage("Form submitted!"); + + //Nested widgets + //Icon button + agHelper.GetNClick( + locators._widgetInDeployed(draggableWidgets.ICONBUTTON), + 1, + ); + assertHelper.WaitForNetworkCall("@postExecute").then((response: any) => { + agHelper.Sleep(); + const name = response.body.data.body[0].name; + agHelper.ValidateToastMessage("Executed api!"); + + //Tab + agHelper.GetNClick(propPane._tabId1); + + //Table + table.SearchTable(name); + table.ReadTableRowColumnData(0, 5, "v2").then(($cellData) => { + expect($cellData).to.contain(name); + }); + table.SelectTableRow(0, 0, true, "v2"); + + //Text + agHelper.ScrollTo(locators._modal, "top"); + agHelper.AssertContains( + name, + "be.visible", + locators._modal + + " " + + locators._widgetInDeployed(draggableWidgets.TEXT), + ); + }); + }); + + it("5. Verify that the Modal widget opens correctly when configured on various events for different widget types.", () => { + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.ICONBUTTON)); + agHelper.AssertElementAbsence(locators._modal); + + //Select - onOptionChanged + agHelper.SelectDropDown("Red"); + agHelper.AssertElementVisibility(locators._modal); + agHelper.AssertContains("Option changed!", "be.visible", locators._modal); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.ICONBUTTON)); + + //List - onItemClick + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.LIST_V2)); + agHelper.AssertContains( + "List Item Clicked!", + "be.visible", + locators._modal, + ); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.ICONBUTTON)); + + //Table - onSearchTextChanged + table.SearchTable("test"); + agHelper.AssertContains( + "Table search value changed!", + "be.visible", + locators._modal, + ); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.ICONBUTTON)); + + //JSON Form - onSubmit + agHelper.TypeText(locators._jsonFormInputField("name"), "test user"); + agHelper.TypeText( + locators._jsonFormInputField("date_of_birth"), + "12/03/1999", + ); + agHelper.TypeText(locators._jsonFormInputField("employee_id"), "1234"); + agHelper.ClickButton("Submit", 1); + agHelper.AssertContains("Form submitted!", "be.visible", locators._modal); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.ICONBUTTON)); + }); + + it("6. Verify modal widget styles", function () { + //JS conversion + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Modal1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Background color", "#fca5a5"); + propPane.EnterJSContext("Border radius", "1.5rem"); + agHelper + .GetWidgetCSSFrAttribute(locators._modalWrapper, "background") + .then((backgroundColor) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.BUTTON), + ); + agHelper.ClickButton("Submit"); + agHelper.AssertCSS( + locators._modalWrapper, + "background", + backgroundColor, + ); + }); + agHelper.AssertCSS(locators._modalWrapper, "border-radius", "24px"); + + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Modal1", "Widgets"); + propPane.MoveToTab("Style"); + //Full color picker + propPane.ToggleJSMode("Background color", false); + propPane.TogglePropertyState("Full color picker", "On"); + agHelper.GetNClick(propPane._propertyControlColorPicker("backgroundcolor")); + agHelper + .GetWidgetCSSFrAttribute(locators._modalWrapper, "background") + .then((backgroundColor) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.BUTTON), + ); + agHelper.ClickButton("Submit"); + agHelper.AssertCSS( + locators._modalWrapper, + "background", + backgroundColor, + ); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiSelect5_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiSelect5_spec.ts new file mode 100644 index 0000000000..4bb61a8052 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiSelect5_spec.ts @@ -0,0 +1,369 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, + dataSources, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Multi Select widget Tests", function () { + before(() => { + entityExplorer.DragDropWidgetNVerify("multiselectwidgetv2", 550, 100); + }); + + it("1. Verify property visibility", function () { + const dataProperties = [ + "sourcedata", + "labelkey", + "valuekey", + "defaultselectedvalues", + ]; + const labelProperties = ["text", "position"]; + const searchfilterProperties = ["allowsearching", "serversidefiltering"]; + const generalProperties = [ + "tooltip", + "placeholder", + "visible", + "disabled", + "animateloading", + "allowselectall", + "height", + ]; + const eventsProperties = [ + "onoptionchange", + "ondropdownopen", + "ondropdownclose", + ]; + const validationsProperties = ["required"]; + + const labelStylesProperties = ["fontcolor", "fontsize"]; + const borderShadows = ["borderradius", "boxshadow"]; + + entityExplorer.SelectEntityByName("MultiSelect1", "Widgets"); + // Data section + dataProperties.forEach((dataSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("data", `${dataSectionProperty}`), + ); + }); + + // Label section + labelProperties.forEach((labelSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "label", + `${labelSectionProperty}`, + ), + ); + }); + + // Search & filters section + searchfilterProperties.forEach((searchSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "search\\&filters", + `${searchSectionProperty}`, + ), + ); + }); + + // General section + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + // Events section + eventsProperties.forEach((eventsSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "events", + `${eventsSectionProperty}`, + ), + ); + }); + + // Validation Section properties + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "validations", + `${validationsProperties}`, + ), + ); + + propPane.MoveToTab("Style"); + labelStylesProperties.forEach((labelStyleSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "labelstyles", + `${labelStyleSectionProperty}`, + ), + ); + }); + borderShadows.forEach((borderShadowSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "borderandshadow", + `${borderShadowSectionProperty}`, + ), + ); + }); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "MultiSelect1", + "NewMultiSelect", + true, + ); + agHelper.AssertElementVisibility(locators._widgetName("NewMultiSelect")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewMultiSelect"); + entityExplorer.AssertEntityPresenceInExplorer("NewMultiSelectCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewMultiSelectCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewMultiSelect"); + propPane.DeleteWidgetFromPropertyPane("NewMultiSelectCopy"); + entityExplorer.SelectEntityByName("NewMultiSelect", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("3. Verify changing Label text and position", () => { + propPane.UpdatePropertyFieldValue("Text", "New Label"); + agHelper.AssertText(locators._label, "text", "New Label"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Left')`); + agHelper.AssertAttribute(locators._label, "position", "Left"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "position", "Left"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "position", "Left"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMultiSelect", "Widgets"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Top')`); + agHelper.AssertAttribute(locators._label, "position", "Top"); + }); + + it("5. Verify tooltip", () => { + entityExplorer.DragDropWidgetNVerify("currencyinputwidget", 550, 300); + propPane.UpdatePropertyFieldValue("Default value", "1000"); + entityExplorer.SelectEntityByName("NewMultiSelect", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "{{CurrencyInput1.text}}"); + agHelper.HoverElement(".bp3-popover-target svg"); + agHelper.AssertPopoverTooltip("1,000"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.HoverElement(".bp3-popover-target svg"); + agHelper.AssertPopoverTooltip("1,000"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.HoverElement(".bp3-popover-target svg"); + agHelper.AssertPopoverTooltip("1,000"); + deployMode.NavigateBacktoEditor(); + }); + + it("6. Validate 'visible' and 'disable' toggle", () => { + entityExplorer.SelectEntityByName("NewMultiSelect"); + + // Verify Disabled toggle + propPane.TogglePropertyState("disabled", "On"); + agHelper.AssertAttribute( + locators._widgetInDeployed("multiselectwidgetv2"), + "disabled", + "disabled", + ); + propPane.TogglePropertyState("disabled", "Off"); + // Verify Visible toggle + propPane.TogglePropertyState("visible", "Off"); + agHelper.AssertAttribute( + locators._widgetInDeployed("multiselectwidgetv2"), + "data-hidden", + "true", + ); + agHelper.AssertExistingToggleState("visible", "false"); + propPane.TogglePropertyState("visible", "On"); + agHelper.AssertExistingToggleState("visible", "true"); + }); + + it("7. Validate auto height with limits", function () { + propPane.SelectPropertiesDropDown("height", "Auto Height with limits"); + agHelper.HoverElement(propPane._autoHeightLimitMin); + agHelper.AssertContains("Min-Height: 4 rows"); + agHelper.HoverElement(propPane._autoHeightLimitMax); + agHelper.AssertContains("Max-Height: 9 rows"); + propPane.SelectPropertiesDropDown("height", "Auto Height"); + }); + + it("7. Validate events onOptionChange, onDropdownOpen and onDropdownClose", function () { + propPane.SelectPlatformFunction("onOptionChange", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Option Changed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.SelectFromMultiSelect(["Blue"]); + agHelper.ValidateToastMessage("Option Changed"); + + // onDropdownOpen + propPane.SelectPlatformFunction("onDropdownOpen", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Dropdown Opened", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + agHelper.GetNClick(propPane._multiSelect); + agHelper.ValidateToastMessage("Dropdown Opened"); + + // Dropdown Close + propPane.SelectPlatformFunction("onDropdownClose", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Dropdown Closed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + agHelper.GetNClick(propPane._multiSelect); + agHelper.GetNClick(propPane._multiSelect); + agHelper.ValidateToastMessage("Dropdown Closed"); + }); + + it("8. Verify Full color picker and font size", () => { + // Verify font color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("fontcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("fontcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + // Font size + propPane.SelectPropertiesDropDown("fontsize", "L"); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "L"); + propPane.ToggleJSMode("fontsize", true); + propPane.UpdatePropertyFieldValue("Font size", "1rem"); + propPane.ToggleJSMode("fontsize", false); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "M"); + // Verify Emphasis + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.AssertAttribute(locators._label, "font-style", "BOLD"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + propPane.ToggleJSMode("emphasis", true); + propPane.UpdatePropertyFieldValue("Emphasis", "ITALIC"); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMultiSelect", "Widgets"); + propPane.MoveToTab("Style"); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS( + `${propPane._multiSelect} .rc-select-selector`, + "border-radius", + "0px", + ); + + // Verify Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + agHelper.AssertCSS( + `${propPane._multiSelect} .rc-select-selector`, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + }); + + it("8. Verify validation error in default selected values", () => { + entityExplorer.SelectEntityByName("NewMultiSelect", "Widgets"); + + propPane.MoveToTab("Content"); + + propPane.UpdatePropertyFieldValue( + "Default selected values", + '["GREEN1", "RED1"]', + true, + ); + + agHelper.VerifyEvaluatedErrorMessage( + "Some or all default values are missing from options. Please update the values.", + ); + + propPane.ToggleJSMode("Source Data", true); + + // Updates the options and asserts that the validation error is fixed + propPane.UpdatePropertyFieldValue( + "Source Data", + '[{"name": "Green", "code":"GREEN1"}, { "name": "Red","code": "RED1" }]', + true, + ); + + agHelper.FocusElement( + locators._propertyInputField("Default selected values"), + ); + + agHelper.Sleep(1000); + agHelper.AssertElementAbsence(locators._evaluatedErrorMessage); + + // Changes options to bring back validation error + propPane.UpdatePropertyFieldValue( + "Source Data", + '[{"name": "Green", "code":"GREEN1"}, { "name": "Red","code": "RED" }]', + true, + ); + + agHelper.FocusElement( + locators._propertyInputField("Default selected values"), + ); + + agHelper.VerifyEvaluatedErrorMessage( + "Some or all default values are missing from options. Please update the values.", + ); + + // Reload to check if the error persists + agHelper.RefreshPage(); + + entityExplorer.SelectEntityByName("NewMultiSelect", "Widgets"); + + agHelper.FocusElement( + locators._propertyInputField("Default selected values"), + ); + + agHelper.VerifyEvaluatedErrorMessage( + "Some or all default values are missing from options. Please update the values.", + ); + + // Fixes the validation error + propPane.UpdatePropertyFieldValue( + "Default selected values", + '{{["GREEN1"]}}', + true, + ); + + agHelper.Sleep(1000); + agHelper.AssertElementAbsence(locators._evaluatedErrorMessage); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiTreeSelect_2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiTreeSelect_2_spec.ts new file mode 100644 index 0000000000..d90e54612b --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiTreeSelect_2_spec.ts @@ -0,0 +1,485 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, + dataSources, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Multi Select widget Tests", function () { + before(() => { + agHelper.AddDsl("multiTreeSelectDsl"); + }); + + it("1. Verify default options are present in dropdown and default selected value", function () { + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.GetNClick(locators._switcherIcon); + agHelper.AssertElementExist(locators._dropDownMultiTreeValue("Blue")); + agHelper.AssertElementExist(locators._dropDownMultiTreeValue("Dark Blue")); + agHelper.AssertElementExist(locators._dropDownMultiTreeValue("Light Blue")); + agHelper.AssertElementExist(locators._dropDownMultiTreeValue("Green")); + agHelper.AssertElementExist(locators._dropDownMultiTreeValue("Red")); + + // Default selected value + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Green", + "have.text", + ); + propPane.UpdatePropertyFieldValue( + "Default selected values", + `[ + "GREEN", + "RED" + ]`, + ); + + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Green", + "have.text", + ); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Red", + "have.text", + 1, + ); + propPane.UpdatePropertyFieldValue( + "Default selected values", + `[ + "GREEN" + ]`, + ); + }); + + it("2. Verify property visibility", function () { + const dataProperties = ["options", "defaultselectedvalues"]; + const labelProperties = ["text", "position"]; + const generalProperties = [ + "tooltip", + "mode", + "placeholder", + "visible", + "disabled", + "animateloading", + "allowclearingvalue", + "expandallbydefault", + "height", + ]; + const eventsProperties = [ + "onoptionchange", + "ondropdownopen", + "ondropdownclose", + ]; + const validationsProperties = ["required"]; + + const labelStylesProperties = ["fontcolor", "fontsize", "emphasis"]; + const borderShadows = ["borderradius", "boxshadow"]; + + entityExplorer.SelectEntityByName("MultiTreeSelect1", "Widgets"); + // Data section + dataProperties.forEach((dataSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("data", `${dataSectionProperty}`), + ); + }); + + // Label section + labelProperties.forEach((labelSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "label", + `${labelSectionProperty}`, + ), + ); + }); + + // General section + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + // Events section + eventsProperties.forEach((eventsSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "events", + `${eventsSectionProperty}`, + ), + ); + }); + + // Validation Section properties + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "validations", + `${validationsProperties}`, + ), + ); + + propPane.MoveToTab("Style"); + labelStylesProperties.forEach((labelStyleSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "labelstyles", + `${labelStyleSectionProperty}`, + ), + ); + }); + borderShadows.forEach((borderShadowSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "borderandshadow", + `${borderShadowSectionProperty}`, + ), + ); + }); + }); + + it("3. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "MultiTreeSelect1", + "NewMultiTreeSelect", + true, + ); + agHelper.AssertElementVisibility( + locators._widgetName("NewMultiTreeSelect"), + ); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewMultiTreeSelect"); + entityExplorer.AssertEntityPresenceInExplorer("NewMultiTreeSelectCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewMultiTreeSelectCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewMultiTreeSelect"); + propPane.DeleteWidgetFromPropertyPane("NewMultiTreeSelectCopy"); + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("4. Validate only selected options are reflected in widget area", () => { + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Red")); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Red", + "have.text", + 1, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Red")); + agHelper.AssertElementAbsence( + `${locators._treeSelectedContent}:contains('Red)`, + ); + + agHelper.GetNClick(locators._switcherIcon); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Dark Blue")); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Dark Blue", + "have.text", + 1, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Dark Blue")); + agHelper.AssertElementAbsence( + `${locators._treeSelectedContent}:contains('Dark Blue)`, + ); + }); + + it("5. Verify changing Label text and position", () => { + propPane.UpdatePropertyFieldValue("Text", "New Label"); + agHelper.AssertText(locators._label, "text", "New Label"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Left')`); + agHelper.AssertAttribute(locators._label, "position", "Left"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "position", "Left"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "position", "Left"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Top')`); + agHelper.AssertAttribute(locators._label, "position", "Top"); + }); + + it("6. Verify tooltip", () => { + entityExplorer.SelectEntityByName("CurrencyInput1", "Widgets"); + propPane.UpdatePropertyFieldValue("Default value", "1000"); + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "{{CurrencyInput1.text}}"); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1,000"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1,000"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1,000"); + deployMode.NavigateBacktoEditor(); + }); + + it("7. Verify Mode options", () => { + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.SelectPropertiesDropDown("Mode", "Display only parent items"); + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.GetNClick(locators._switcherIcon); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Dark Blue")); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Light Blue")); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Blue", + "have.text", + 1, + ); + + propPane.SelectPropertiesDropDown("Mode", "Display only child items"); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Dark Blue", + "have.text", + 1, + ); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Light Blue", + "have.text", + 2, + ); + + propPane.SelectPropertiesDropDown("Mode", "Display all items"); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Blue", + "have.text", + 1, + ); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Dark Blue", + "have.text", + 2, + ); + agHelper.GetNAssertElementText( + locators._treeSelectedContent, + "Light Blue", + "have.text", + 3, + ); + }); + + it("8. Verify placeholder", function () { + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Blue")); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Green")); + propPane.UpdatePropertyFieldValue("Placeholder", "Select new option"); + agHelper.AssertText( + locators._treeSelectPlaceholder, + "text", + "Select new option", + ); + // Binding with Text widget + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.UpdatePropertyFieldValue("Text", "Select value"); + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.UpdatePropertyFieldValue("Placeholder", "{{Text1.text}}"); + agHelper.AssertText( + locators._treeSelectPlaceholder, + "text", + "Select value", + ); + }); + + it("9. Validate visible and disabled toggle", () => { + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.TogglePropertyState("visible", "Off"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("multiselecttreewidget"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("multiselecttreewidget"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.TogglePropertyState("visible", "On"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("multiselecttreewidget"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("multiselecttreewidget"), + ); + deployMode.NavigateBacktoEditor(); + + // Visible JS mode + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "false"); + + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("multiselecttreewidget"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "true"); + propPane.ToggleJSMode("Visible", false); + + // Disabled + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.TogglePropertyState("disabled", "On"); + agHelper.AssertAttribute( + locators._widgetInDeployed("multiselecttreewidget"), + "disabled", + "disabled", + ); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute( + locators._widgetInDeployed("multiselecttreewidget"), + "disabled", + "disabled", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute( + locators._widgetInDeployed("multiselecttreewidget"), + "disabled", + "disabled", + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.TogglePropertyState("disabled", "Off"); + }); + + it("10. Validate auto height with limits", function () { + propPane.SelectPropertiesDropDown("height", "Auto Height with limits"); + agHelper.HoverElement(propPane._autoHeightLimitMin); + agHelper.AssertContains("Min-Height: 4 rows"); + agHelper.HoverElement(propPane._autoHeightLimitMax); + agHelper.AssertContains("Max-Height: 13 rows"); + propPane.SelectPropertiesDropDown("height", "Auto Height"); + }); + + it("11. Validate events onOptionChange, onDropdownOpen and onDropdownClose", function () { + propPane.SelectPlatformFunction("onOptionChange", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Option Changed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Red")); + agHelper.ValidateToastMessage("Option Changed"); + + // onDropdownOpen + propPane.SelectPlatformFunction("onDropdownOpen", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Dropdown Opened", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.ValidateToastMessage("Dropdown Opened"); + + // Dropdown Close + propPane.SelectPlatformFunction("onDropdownClose", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Dropdown Closed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.GetNClick(locators._dropDownMultiTreeSelect); + agHelper.ValidateToastMessage("Dropdown Closed"); + }); + + it("12. Verify Full color picker and font size", () => { + // Verify font color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("fontcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("fontcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + // Font size + propPane.SelectPropertiesDropDown("fontsize", "L"); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "L"); + propPane.ToggleJSMode("fontsize", true); + propPane.UpdatePropertyFieldValue("Font size", "1rem"); + propPane.ToggleJSMode("fontsize", false); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "M"); + // Verify Emphasis + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.AssertAttribute(locators._label, "font-style", "BOLD"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + propPane.ToggleJSMode("emphasis", true); + propPane.UpdatePropertyFieldValue("Emphasis", "ITALIC"); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMultiTreeSelect", "Widgets"); + propPane.MoveToTab("Style"); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS(".rc-tree-select-selector", "border-radius", "0px"); + + // Verify Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + agHelper.AssertCSS( + ".rc-tree-select-selector", + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + propPane.MoveToTab("Content"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/Multi_Select_Tree_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/Multi_Select_Tree_spec.js index 8ff4bbe956..da80af016d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/Multi_Select_Tree_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/Multi_Select_Tree_spec.js @@ -24,7 +24,11 @@ describe("MultiSelectTree Widget Functionality", function () { // Check if isDirty is set to false cy.get(".t--widget-textwidget").should("contain", "false"); // Interact with UI - cy.get(formWidgetsPage.treeSelectInput).first().click({ force: true }); + cy.wait(1000) + .get(formWidgetsPage.treeSelectInput) + .first() + .click({ force: true }) + .wait(500); cy.treeMultiSelectDropdown("Red"); // Check if isDirty is set to true cy.get(".t--widget-textwidget").should("contain", "true"); @@ -42,7 +46,11 @@ describe("MultiSelectTree Widget Functionality", function () { .first() .should("have.text", "Red"); // Clear the selected value - cy.get(formWidgetsPage.treeSelectInput).first().click({ force: true }); + cy.wait(1000) + .get(formWidgetsPage.treeSelectInput) + .first() + .click({ force: true }) + .wait(500); cy.treeMultiSelectDropdown("Red"); }); @@ -51,7 +59,11 @@ describe("MultiSelectTree Widget Functionality", function () { // search for option Red in the search input cy.openPropertyPane("multiselecttreewidget"); cy.testJsontext("defaultselectedvalues", ""); - cy.get(formWidgetsPage.treeSelectInput).first().click({ force: true }); + cy.wait(2000) + .get(formWidgetsPage.treeSelectInput) + .first() + .click({ force: true }) + .wait(500); cy.get(formWidgetsPage.multiTreeSelectFilterInput) .click({ force: true }) .type("Green"); @@ -63,7 +75,11 @@ describe("MultiSelectTree Widget Functionality", function () { .first() .should("have.text", "Green"); // Reopen the multi-tree select widget - cy.get(formWidgetsPage.treeSelectInput).first().click({ force: true }); + cy.wait(1000) + .get(formWidgetsPage.treeSelectInput) + .first() + .click({ force: true }) + .wait(500); // Assert if the search input is empty now cy.get(formWidgetsPage.multiTreeSelectFilterInput) .invoke("val") @@ -73,7 +89,11 @@ describe("MultiSelectTree Widget Functionality", function () { }); it("4. To Validate Options", function () { - cy.get(formWidgetsPage.treeSelectInput).first().click({ force: true }); + cy.wait(1000) + .get(formWidgetsPage.treeSelectInput) + .first() + .click({ force: true }) + .wait(500); cy.get(formWidgetsPage.multiTreeSelectFilterInput).click().type("light"); cy.treeMultiSelectDropdown("Light Blue"); }); @@ -98,7 +118,11 @@ describe("MultiSelectTree Widget Functionality", function () { }); it("7. To Check Option Not Found", function () { - cy.get(formWidgetsPage.treeSelectInput).first().click({ force: true }); + cy.wait(1000) + .get(formWidgetsPage.treeSelectInput) + .first() + .click({ force: true }) + .wait(500); cy.get(formWidgetsPage.multiTreeSelectFilterInput).click().type("ABCD"); cy.get(".tree-multiselect-dropdown .rc-tree-select-empty").contains( "No Results Found", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/RTL_support.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/RTL_support.ts new file mode 100644 index 0000000000..03138ed27c --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/RTL_support.ts @@ -0,0 +1,71 @@ +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; +import { + agHelper, + draggableWidgets, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Select Widget", () => { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.MULTISELECT); + }); + + it("1. Test RTL support", () => { + featureFlagIntercept({ + license_widget_rtl_support_enabled: false, + }); + + agHelper.AssertElementAbsence(".t--property-control-enablertl"); + + featureFlagIntercept({ + license_widget_rtl_support_enabled: true, + }); + + agHelper.RefreshPage(); + + agHelper.Sleep(2000); + + agHelper.AssertElementExist(".t--property-control-enablertl"); + + propPane.TogglePropertyState("Enable RTL", "On"); + + agHelper + .GetElement(".t--widget-multiselectwidgetv2 .rc-select-selector") + .click(); + + agHelper + .GetElement( + ".t--widget-multiselectwidgetv2 [data-testid='multiselect-container']", + ) + .should("have.css", "direction", "rtl"); + + agHelper + .GetElement(".t--widget-multiselectwidgetv2 .rc-select-selector") + .should("have.css", "direction", "rtl"); + + agHelper + .GetElement(".multi-select-dropdown input.bp3-input") + .should("have.css", "direction", "rtl"); + + agHelper.GetElement(".rc-select-dropdown [dir='rtl']").should("exist"); + + propPane.TogglePropertyState("Enable RTL", "Off"); + + agHelper + .GetElement( + ".t--widget-multiselectwidgetv2 [data-testid='multiselect-container']", + ) + .should("have.css", "direction", "ltr"); + + agHelper + .GetElement(".t--widget-multiselectwidgetv2 .rc-select-selector") + .should("have.css", "direction", "ltr"); + + agHelper + .GetElement(".multi-select-dropdown input.bp3-input") + .should("have.css", "direction", "ltr"); + + agHelper.GetElement(".rc-select-dropdown [dir='rtl']").should("not.exist"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/Autocomplete_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/Autocomplete_spec.js index 159958ac92..9cca4d369a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/Autocomplete_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/Autocomplete_spec.js @@ -13,7 +13,7 @@ describe("Autocomplete using slash command and mustache tests", function () { // validates all autocomplete commands on entering / in label field cy.get(`${dynamicInputLocators.hints} li`) .eq(0) - .should("have.text", "New binding"); + .should("have.text", "Add a binding"); cy.get(`${dynamicInputLocators.hints} li`) .last() .should("have.text", "New datasource"); @@ -39,13 +39,16 @@ describe("Autocomplete using slash command and mustache tests", function () { cy.get(".t--property-control-onclick .CodeMirror textarea") .last() .focus() + .type("{uparrow}", { parseSpecialCharSequences: true }) + .type("{ctrl}{shift}{downarrow}", { parseSpecialCharSequences: true }) + .type("{backspace}", { parseSpecialCharSequences: true }) .type("/") .then(() => { cy.get(dynamicInputLocators.hints).should("exist"); // validates all autocomplete commands on entering / in onClick field cy.get(`${dynamicInputLocators.hints} li`) .eq(0) - .should("have.text", "New binding"); + .should("have.text", "Add a binding"); cy.get(`${dynamicInputLocators.hints} li`) .last() .should("have.text", "New datasource"); @@ -59,16 +62,8 @@ describe("Autocomplete using slash command and mustache tests", function () { .type("{shift}{{}{shift}{{}") .then(() => { cy.get(dynamicInputLocators.hints).should("exist"); - // validates all autocomplete functions on entering {{}} in onClick field - cy.get(`${dynamicInputLocators.hints} li`) - .eq(7) - .should("have.text", "storeValue()"); - cy.get(`${dynamicInputLocators.hints} li`) - .eq(8) - .should("have.text", "showAlert()"); - cy.get(`${dynamicInputLocators.hints} li`) - .eq(9) - .should("have.text", "navigateTo()"); + _.agHelper.AssertContains("storeValue"); + _.agHelper.AssertContains("showAlert"); }); }); @@ -83,7 +78,7 @@ describe("Autocomplete using slash command and mustache tests", function () { // validates all autocomplete commands on entering / in text field cy.get(`${dynamicInputLocators.hints} li`) .eq(0) - .should("have.text", "New binding"); + .should("have.text", "Add a binding"); cy.get(`${dynamicInputLocators.hints} li`) .last() .should("have.text", "New datasource"); @@ -98,13 +93,8 @@ describe("Autocomplete using slash command and mustache tests", function () { cy.get(dynamicInputLocators.input) .first() .type("{shift}{{}{shift}{{}"); - // validates autocomplete binding on entering {{}} in text field - cy.get(`${dynamicInputLocators.hints} li`) - .eq(1) - .should("have.text", "Button1.text"); - cy.get(`${dynamicInputLocators.hints} li`) - .eq(2) - .should("have.text", "Button1.recaptchaToken"); + _.agHelper.AssertContains("Button1.text"); + _.agHelper.AssertContains("Button1.recaptchaToken"); }); }, ); @@ -120,7 +110,7 @@ describe("Autocomplete using slash command and mustache tests", function () { // validates all autocomplete commands on entering / in text field cy.get(`${dynamicInputLocators.hints} li`) .eq(0) - .should("have.text", "New binding"); + .should("have.text", "Add a binding"); cy.get(`${dynamicInputLocators.hints} li`) .last() .should("have.text", "New datasource"); @@ -144,83 +134,32 @@ describe("Autocomplete using slash command and mustache tests", function () { ); it("Bug 9003: Autocomplete not working for Appsmith specific JS APIs", function () { - cy.openPropertyPane("buttonwidget"); - cy.get(".t--property-control-onclick") - .find(".t--js-toggle") - .click({ force: true }); - cy.EnableAllCodeEditors(); - cy.get(".CodeMirror textarea") - .last() - .focus() - .clear() - .type("{{re") - .then(() => { - cy.get(dynamicInputLocators.hints).should("exist"); - // validates autocomplete suggestion for resetWidget() in onClick field - cy.get(`${dynamicInputLocators.hints} li`) - .eq(0) - .should("have.text", "removeValue()"); - cy.get(`${dynamicInputLocators.hints} li`) - .eq(1) - .should("have.text", "resetWidget()"); - }); - cy.EnableAllCodeEditors(); - cy.get(".CodeMirror textarea") - .last() - .focus() - // clearing the onClick field - .type("{ctrl}{shift}{uparrow}", { parseSpecialCharSequences: true }) - .type("{backspace}", { parseSpecialCharSequences: true }) - .type("{rightarrow}{rightarrow}", { parseSpecialCharSequences: true }) - .type("{ctrl}{shift}{uparrow}", { parseSpecialCharSequences: true }) - .type("{backspace}", { parseSpecialCharSequences: true }) - .type("{{s") - .then(() => { - cy.get(dynamicInputLocators.hints).should("exist"); - // validates autocomplete function suggestions on entering '{{s' in onClick field - cy.get(`${dynamicInputLocators.hints} li`) - .should("contain.text", "storeValue()") - .and("contain.text", "showModal()") - .and("contain.text", "setInterval()") - .and("contain.text", "showAlert()"); - }); - cy.EnableAllCodeEditors(); - cy.get(".CodeMirror textarea") - .last() - .focus() - // clearing the onClick field - .type("{ctrl}{shift}{uparrow}", { parseSpecialCharSequences: true }) - .type("{backspace}", { parseSpecialCharSequences: true }) - .type("{rightarrow}{rightarrow}", { parseSpecialCharSequences: true }) - .type("{ctrl}{shift}{uparrow}", { parseSpecialCharSequences: true }) - .type("{backspace}", { parseSpecialCharSequences: true }) - .type("{{c") - .then(() => { - cy.get(dynamicInputLocators.hints).should("exist"); - // validates autocomplete function suggestions on entering '{{c' in onClick field - cy.get(`${dynamicInputLocators.hints} li`) - .should("contain.text", "closeModal()") - .and("contain.text", "copyToClipboard()") - .and("contain.text", "clearInterval()") - .and("contain.text", "clearStore()"); - }); - cy.EnableAllCodeEditors(); - cy.get(".CodeMirror textarea") - .last() - .focus() - .type("{ctrl}{shift}{uparrow}", { parseSpecialCharSequences: true }) - .type("{backspace}", { parseSpecialCharSequences: true }) - .type("{rightarrow}{rightarrow}", { parseSpecialCharSequences: true }) - .type("{ctrl}{shift}{uparrow}", { parseSpecialCharSequences: true }) - .type("{backspace}", { parseSpecialCharSequences: true }) - .type("{{n") - .then(() => { - cy.get(dynamicInputLocators.hints).should("exist"); - // validates autocomplete suggestions on entering '{{n' in onClick field - cy.get(`${dynamicInputLocators.hints} li`).should( - "contain.text", - "navigateTo()", - ); - }); + _.entityExplorer.SelectEntityByName("Button1", "Widgets"); + _.propPane.ToggleJSMode("onClick", true); + _.propPane.TypeTextIntoField("onClick", "{{storeValue", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "storeValue"); + _.propPane.TypeTextIntoField("onClick", "{{removeValue", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "removeValue"); + _.propPane.TypeTextIntoField("onClick", "{{showAlert", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "showAlert"); + _.propPane.TypeTextIntoField("onClick", "{{setInterval", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "setInterval"); + _.propPane.TypeTextIntoField("onClick", "{{setTimeout", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "setTimeout"); + _.propPane.TypeTextIntoField("onClick", "{{resetWidget", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "resetWidget"); + _.propPane.TypeTextIntoField("onClick", "{{showModal", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "showModal"); + _.propPane.TypeTextIntoField("onClick", "{{copyToClipboard", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "copyToClipboard"); + _.propPane.TypeTextIntoField("onClick", "{{closeModal", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "closeModal"); + _.propPane.TypeTextIntoField("onClick", "{{Text1.setDisabled", true); + _.agHelper.GetNAssertElementText(_.locators._hints, "setDisabled"); + + _.propPane.TypeTextIntoField("Label", "{{storeValue", true); + _.agHelper.AssertElementAbsence(_.locators._hints); + _.propPane.TypeTextIntoField("Label", "{{Text1.setDisabled", true); + _.agHelper.AssertElementAbsence(_.locators._hints); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/IconButton_2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/IconButton_2_spec.ts new file mode 100644 index 0000000000..e5c1c5c1f9 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/IconButton_2_spec.ts @@ -0,0 +1,274 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, + draggableWidgets, + assertHelper, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Icon Button widget Tests", function () { + before(() => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.ICONBUTTON); + entityExplorer.DragDropWidgetNVerify( + draggableWidgets.CURRENCY_INPUT, + 200, + 600, + ); + + entityExplorer.SelectEntityByName("IconButton1", "Widgets"); + }); + + it("1. Verify property visibility", function () { + const basicProperties = ["icon", "onclick"]; + + const generalProperties = [ + "tooltip", + "visible", + "disabled", + "animateloading", + ]; + + const styleGeneralProperties = ["buttonvariant"]; + + const styleColorProperties = ["buttoncolor"]; + + const styleBorderProperties = ["borderradius", "boxshadow"]; + + propPane.AssertPropertyVisibility(basicProperties, "basic"); + propPane.AssertPropertyVisibility(generalProperties, "general"); + propPane.MoveToTab("Style"); + propPane.AssertPropertyVisibility(styleGeneralProperties, "general"); + propPane.AssertPropertyVisibility(styleColorProperties, "color"); + propPane.AssertPropertyVisibility(styleBorderProperties, "borderandshadow"); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "IconButton1", + "NewIconButton", + true, + ); + agHelper.AssertElementVisibility(locators._widgetName("NewIconButton")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewIconButton"); + entityExplorer.AssertEntityPresenceInExplorer("NewIconButtonCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewIconButtonCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewIconButton"); + propPane.DeleteWidgetFromPropertyPane("NewIconButtonCopy"); + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("3. Validate icon can be selected from dropdown and icon can be searched by typing", () => { + // Select from dropdown + agHelper.GetNClick(`${locators._propertyControl}icon`); + agHelper.GetElement(propPane._iconDropdown).scrollTo("top"); + agHelper.Sleep(); + agHelper.GetNClick(propPane._dataIcon("airplane")); + agHelper.AssertElementVisibility( + `${locators._widgetInDeployed("iconbuttonwidget")} ${propPane._dataIcon( + "airplane", + )}`, + ); + + // Type and select + agHelper.GetNClick(`${locators._propertyControl}icon`); + agHelper.TypeText(`[placeholder="Filter..."]${locators._input}`, "flame"); + agHelper.AssertElementVisibility(propPane._dataIcon("flame")); + agHelper.GetNClick(propPane._dataIcon("flame")); + agHelper.AssertElementVisibility( + `${locators._widgetInDeployed("iconbuttonwidget")} ${propPane._dataIcon( + "flame", + )}`, + ); + + // Icon can be set in JS mode + propPane.ToggleJSMode("Icon", true); + propPane.UpdatePropertyFieldValue("Icon", "add"); + agHelper.AssertElementVisibility( + `${locators._widgetInDeployed("iconbuttonwidget")} ${propPane._dataIcon( + "add", + )}`, + ); + }); + + it("4. Verify onClick", () => { + propPane.ToggleJSMode("onClick", true); + propPane.UpdatePropertyFieldValue( + "onClick", + "{{navigateTo('www.yahoo.com', {}, 'SAME_WINDOW');}}", + ); + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.ICONBUTTON), + ); + agHelper.GetNClick(`${locators._widgetInDeployed("iconbuttonwidget")}`); + agHelper.AssertURL("yahoo.com"); + // agHelper.BrowserNavigation(-1); + cy.window({ timeout: 60000 }).then((win) => { + win.history.back(); + }); + assertHelper.AssertNetworkResponseData("@viewPage"); + assertHelper.AssertDocumentReady(); + agHelper.Sleep(3000); //for view page to complete loading & then navigate back + deployMode.NavigateBacktoEditor(); + }); + + it("5. Verify tooltip", () => { + // entityExplorer.DragDropWidgetNVerify("currencyinputwidget", 500, 300); + entityExplorer.SelectEntityByName("CurrencyInput1", "Widgets"); + propPane.UpdatePropertyFieldValue("Default value", "1000"); + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "{{CurrencyInput1.text}}"); + agHelper + .GetElement(locators._widgetInDeployed("iconbuttonwidget")) + .realHover(); + agHelper.AssertPopoverTooltip("1,000"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper + .GetElement(locators._widgetInDeployed("iconbuttonwidget")) + .realHover(); + agHelper.AssertPopoverTooltip("1,000"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper + .GetElement(locators._widgetInDeployed("iconbuttonwidget")) + .realHover(); + agHelper.AssertPopoverTooltip("1,000"); + deployMode.NavigateBacktoEditor(); + }); + + it("6. Validate visible and disabled toggle", () => { + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.TogglePropertyState("visible", "Off"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("iconbuttonwidget"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("iconbuttonwidget"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.TogglePropertyState("visible", "On"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("iconbuttonwidget"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("iconbuttonwidget"), + ); + deployMode.NavigateBacktoEditor(); + + // Visible JS mode + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "false"); + + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("iconbuttonwidget"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "true"); + propPane.ToggleJSMode("Visible", false); + + // Disabled + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.TogglePropertyState("disabled", "On"); + agHelper.AssertAttribute( + locators._widgetInDeployed("iconbuttonwidget"), + "disabled", + "disabled", + ); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute( + locators._widgetInDeployed("iconbuttonwidget"), + "disabled", + "disabled", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute( + locators._widgetInDeployed("iconbuttonwidget"), + "disabled", + "disabled", + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewIconButton", "Widgets"); + propPane.TogglePropertyState("disabled", "Off"); + }); + + it("7. Verify button color and border and shadows", () => { + // Verify button color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("buttoncolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("buttoncolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + + // Verify Button variant + agHelper.AssertCSS( + locators._buttonInDeployedMode, + "background-color", + "rgb(85, 61, 233)", + ); + agHelper.GetNClick(propPane._segmentedControl("SECONDARY")); + agHelper.AssertCSS( + locators._buttonInDeployedMode, + "background-color", + "rgba(0, 0, 0, 0)", + ); + propPane.ToggleJSMode("Button variant", true); + propPane.UpdatePropertyFieldValue("Button variant", "PRIMARY"); + agHelper.AssertCSS( + locators._buttonInDeployedMode, + "background-color", + "rgb(85, 61, 233)", + ); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS(locators._buttonInDeployedMode, "border-radius", "0px"); + + // Verify Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + agHelper.AssertCSS( + locators._buttonInDeployedMode, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapChart_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapChart_Spec.ts new file mode 100644 index 0000000000..531ee65a22 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapChart_Spec.ts @@ -0,0 +1,220 @@ +/// +import viewWidgetsPage from "../../../../../locators/ViewWidgets.json"; +import { + agHelper, + entityExplorer, + propPane, + draggableWidgets, + deployMode, + locators, +} from "../../../../../support/Objects/ObjectsCore"; + +const _mapChartCaption = "g[class*='-caption'] text"; +const _mapChartPlot = (text: string) => + "//text()[contains(., '" + text + "')]/.."; + +describe("Map Chart Widget Functionality", function () { + it("1. Drag and drop a Map Chart widget and verify", function () { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MAPCHART, 200, 200); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapchartsimple"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + }); + + it("2.1 Update the Map type to different types and verify - part1", function () { + // Change the map type to World with Antarctica and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "World with Antarctica"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 7); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithantarctica"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change the map type to World and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "World"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 6); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithworld"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change the map type to Europe and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "Europe"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 47); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwitheurope"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change the map type to North America and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "North America"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 26); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithnorthamerica"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change the map type to South America and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "South America"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 16); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithsouthamerica"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + }); + + it("2.2 Update the Map type to different types and verify - part2", function () { + // Change the map type to Oceania and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "Oceania"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 15); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithoceania"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change the map type to Africa and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "Africa"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 56); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithafrica"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change the map type to USA and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "USA"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 51); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithusa"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change the map type to Asia and verify the number of entities + propPane.SelectPropertiesDropDown("Map type", "Asia"); + agHelper.AssertElementLength(viewWidgetsPage.mapChartEntityLabels, 49); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithasia"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + }); + + it("3. Update the Chart data and verify", function () { + const data = [ + { + id: "014", + value: "2", + }, + ]; + + propPane.TypeTextIntoField("Chart data", JSON.stringify(data)); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithcustomdata"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + }); + + it("4. Verify General settings", function () { + // update the title and verify + propPane.TypeTextIntoField("Title", "App Sign Up"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.AssertText(_mapChartCaption, "text", "App Sign Up"); + agHelper.VerifySnapshot(locators._root, "mapwithcustomtitle"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // update the visibility using toggle and verify + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.MAPCHART), + ); + agHelper.VerifySnapshot(locators._root, "mapwithvisibilityoff"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // update the visibility using JS and verify + propPane.EnterJSContext("Visible", "true"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.MAPCHART), + ); + agHelper.VerifySnapshot(locators._root, "mapwithvisibilityon"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // update the show labels using toggle and verify + propPane.TogglePropertyState("Show Labels", "Off"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithshowlabelsoff"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // update the visibility using JS and verify + propPane.EnterJSContext("Show Labels", "true"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapwithshowlableson"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + }); + + it("5. Update onDataPointClick and Verify", function () { + // Create the Alert Modal and verify Modal name + propPane.SelectPropertiesDropDown("Map type", "Asia"); + propPane.SelectPlatformFunction("onDataPointClick", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Data Point {{MapChart1.selectedDataPoint.label}} Clicked", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.GetNClick(_mapChartPlot("RU"), 0, true); + agHelper.ValidateToastMessage("Data Point Russian Federation Clicked"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Convert the onDataPointClick to JS, update and verify + propPane.EnterJSContext( + "onDataPointClick", + "{{showAlert('Converted to Js and clicked '+ MapChart1.selectedDataPoint.label)}}", + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.GetNClick(_mapChartPlot("CN"), 0, true); + agHelper.ValidateToastMessage("Converted to Js and clicked China"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + }); + + it("6. Verify the style changes", function () { + // Change Color Range and verify + const colorRange = [ + { + minValue: 2, + maxValue: 3, + code: "#FFFFF", + }, + ]; + propPane.MoveToTab("Style"); + propPane.TypeTextIntoField("Color Range", JSON.stringify(colorRange)); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapChartWithColorRange"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change border radius and verify + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Border radius", "1.5rem"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapChartWithBorderRadius"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("MapChart1", "Widgets"); + + // Change box shadow and verify + const boxShadow = + "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)"; + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Box shadow", boxShadow); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAPCHART)); + agHelper.VerifySnapshot(locators._root, "mapChartWithBoxShadow"); + deployMode.NavigateBacktoEditor(); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapChart_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapChart_spec.js deleted file mode 100644 index 55b9454998..0000000000 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapChart_spec.js +++ /dev/null @@ -1,152 +0,0 @@ -const commonLocators = require("../../../../../locators/commonlocators.json"); -const viewWidgetsPage = require("../../../../../locators/ViewWidgets.json"); -const widgetsPage = require("../../../../../locators/Widgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; - -describe("Map Chart Widget Functionality", function () { - before(() => { - _.agHelper.AddDsl("MapChartDsl"); - }); - - beforeEach(() => { - _.entityExplorer.SelectEntityByName("MapChart1", "Widgets"); - }); - - afterEach(() => { - _.deployMode.NavigateBacktoEditor(); - }); - - it("1. Change Title", function () { - cy.testJsontext("title", this.dataSet.chartIndata); - cy.get(viewWidgetsPage.chartInnerText) - .contains("App Sign Up") - .should("have.text", "App Sign Up"); - _.deployMode.DeployApp(); - }); - - it("2. Show Labels: FALSE", function () { - cy.togglebarDisable(commonLocators.mapChartShowLabels); - cy.get(viewWidgetsPage.mapChartEntityLabels).should("not.exist"); - _.deployMode.DeployApp(); - // Show Labels: TRUE - _.deployMode.NavigateBacktoEditor(); - _.entityExplorer.SelectEntityByName("MapChart1", "Widgets"); - cy.togglebar(commonLocators.mapChartShowLabels); - cy.get(viewWidgetsPage.mapChartEntityLabels).eq(1).should("exist"); - _.deployMode.DeployApp(); - }); - - it("3. Map type: World with Antarctica", function () { - // Change the map type - cy.updateMapType("World with Antarctica"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 7); - _.deployMode.DeployApp(); - }); - - it("4. Map type: World", function () { - // Change the map type - cy.updateMapType("World"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 6); - _.deployMode.DeployApp(); - }); - - it("5. Map type: Europe", function () { - // Change the map type - cy.updateMapType("Europe"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 47); - _.deployMode.DeployApp(); - }); - - it("6. Map type: North America", function () { - // Change the map type - cy.updateMapType("North America"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 26); - _.deployMode.DeployApp(); - }); - - it("7. Map type: South America", function () { - // Change the map type - cy.updateMapType("South America"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 16); - _.deployMode.DeployApp(); - }); - - it("8. Map type: Asia", function () { - // Change the map type - cy.updateMapType("Asia"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 49); - _.deployMode.DeployApp(); - }); - - it("9. Map type: Oceania", function () { - // Change the map type - cy.updateMapType("Oceania"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 15); - _.deployMode.DeployApp(); - }); - - it("10. Map type: Africa", function () { - // Change the map type - cy.updateMapType("Africa"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 56); - _.deployMode.DeployApp(); - }); - - it("11. Map type: USA", function () { - // Change the map type - cy.updateMapType("USA"); - // Verify the number of entities - cy.get(viewWidgetsPage.mapChartEntityLabels).should("have.length", 51); - _.deployMode.DeployApp(); - }); - - it("12. Action: onDataPointClick, Open modal", function () { - // Create the Alert Modal and verify Modal name - cy.createModal(this.dataSet.ModalName, "onDataPointClick"); - _.deployMode.DeployApp(); - /* - cy.get(widgetsPage.mapChartPlot) - .children() - .first() - .click({ force: true }); - cy.get(modalWidgetPage.modelTextField).should( - "have.text", - this.dataSet.ModalName, - ); - */ - }); - - it("13. Action: onDataPointClick, Show message using selectedDataPoint", function () { - cy.get(_.locators._jsToggle("ondatapointclick")).scrollIntoView().click(); - _.propPane.UpdatePropertyFieldValue("onDataPointClick", ""); - cy.get(_.locators._jsToggle("ondatapointclick")).click(); - - const expectedEntityData = { - value: 2.04, - label: "South America", - shortLabel: "SA", - originalId: "SA", - id: "sa", - }; - // Set the map type to default - cy.updateMapType("World"); - // Set action details for onDataPointClick - const boundMessage = `{{JSON.stringify(MapChart1.selectedDataPoint)}}`; - cy.addAction(boundMessage, "onDataPointClick"); - cy.get(commonLocators.chooseMsgType).last().click({ force: true }); - cy.get(commonLocators.chooseAction).children().contains("Success").click(); - // Click on the entity, South America - cy.get(widgetsPage.mapChartPlot).children().first().click({ force: true }); - // Assert - cy.validateToastMessage(JSON.stringify(expectedEntityData)); - _.deployMode.DeployApp(); - }); -}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapWidget_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapWidget_Spec.ts new file mode 100644 index 0000000000..db84eaccfa --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MapWidget_Spec.ts @@ -0,0 +1,164 @@ +/// +import { + agHelper, + entityExplorer, + propPane, + draggableWidgets, + deployMode, + locators, +} from "../../../../../support/Objects/ObjectsCore"; + +const location = [ + { + lat: 28.7040592, + long: 77.10249019999999, + title: "Delhi, India", + }, + { + lat: 28.4594965, + long: 77.0266383, + title: "Gurugram, Haryana, India", + }, + { + lat: 40.7127753, + long: -74.0059728, + title: "New York, NY, USA", + }, +]; + +describe("Map Widget", function () { + it("1.Drag Map Widget and Verify the Map Widget with Initial Location", () => { + //Add map and verify + entityExplorer.DragDropWidgetNVerify(draggableWidgets.MAP, 200, 200); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapsimple"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Add Initial location and verify + propPane.TypeTextIntoField("Initial location", "New York, NY, USA"); + agHelper.PressEnter(); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithInitalLocation"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // convert Initial location to JS, update and verify + propPane.EnterJSContext("Initial location", JSON.stringify(location[0])); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithinItalLocationAsJS"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + }); + + it("2.Verify the Map Widget with Default markers", () => { + // With single default marker + propPane.TypeTextIntoField( + "Default Markers", + JSON.stringify(location.slice(0, 1)), + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithDefaultMarker1"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // With multiple default marker + propPane.TypeTextIntoField( + "Default Markers", + JSON.stringify(location.slice(0, 2)), + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithDefaultMarker2"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + }); + + it("3.Verify the Map Widget with zoom level", () => { + // With multiple default marker + propPane.SetZoomLevel(70); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithDefaultZoomOut"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Zoom in and verify + propPane.SetZoomLevel(30); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithDefaultZoomIn"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + }); + + it("4.1 Verify the Map Widget with different general settings", () => { + // With visibility off + propPane.TogglePropertyState("Visible", "Off"); + deployMode.DeployApp(); + agHelper.VerifySnapshot(locators._root, "mapWithVisibilityOff"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Convert visibility to JS and set the visibility "On" and verify + propPane.EnterJSContext("Visible", "true"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithVisibilityOnWithJS"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Toggle off Enable pick location and verify + propPane.TogglePropertyState("Enable pick location", "Off"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithPickLocationOff"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Toggle off Map & marker centering and verify + propPane.TogglePropertyState("Map & marker centering", "Off"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithMapNMarkerCenteringOff"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + }); + + it("4.2 Verify the Map Widget with different general settings", () => { + // Toggle On Enabling clustering and verify + propPane.TogglePropertyState("Enable clustering", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithEnablingClusteringON"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Convert Enabling clustering and disable it and verify + propPane.EnterJSContext("Enable clustering", "false"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithEnablingClusteringOff"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Toggle off Enable search location and verify + propPane.TogglePropertyState("Enable search location", "Off"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithEnableSearchLocationOff"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + }); + + it("5 Verify the style changes", () => { + // Change border radius and verify + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Border radius", "1.5rem"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithBorderRadius"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + + // Change box shadow and verify + const boxShadow = + "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)"; + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Box shadow", boxShadow); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.MAP)); + agHelper.VerifySnapshot(locators._root, "mapWithBoxShadow"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Map1", "Widgets"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MenuButtonTest.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MenuButtonTest.ts new file mode 100644 index 0000000000..ab3b62ef6a --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/MenuButtonTest.ts @@ -0,0 +1,238 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, + table, +} from "../../../../../support/Objects/ObjectsCore"; +import { buttongroupwidgetlocators } from "../../../../../locators/WidgetLocators"; + +describe("Menu Button widget Tests", function () { + before(() => { + agHelper.AddDsl("menuButtonDsl"); + }); + + it("1. Verify property visibility", function () { + const basicProperties = ["label", "menuitemssource", "menuitems"]; + const generalProperties = [ + "visible", + "disabled", + "animateloading", + "compact", + ]; + + const styleGeneralProperties = ["buttonvariant"]; + const styleIconProperties = ["icon", "position", "placement"]; + const colorProperties = ["buttoncolor"]; + const styleBorderProperties = ["borderradius", "boxshadow"]; + + entityExplorer.SelectEntityByName("MenuButton1", "Widgets"); + + basicProperties.forEach((basicSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "basic", + `${basicSectionProperty}`, + ), + ); + }); + + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + propPane.MoveToTab("Style"); + + styleGeneralProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + styleIconProperties.forEach((iconSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("icon", `${iconSectionProperty}`), + ); + }); + + colorProperties.forEach((colorSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "color", + `${colorSectionProperty}`, + ), + ); + }); + + styleBorderProperties.forEach((borderSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "borderandshadow", + `${borderSectionProperty}`, + ), + ); + }); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "MenuButton1", + "NewMenuButton", + true, + ); + agHelper.AssertElementVisibility(locators._widgetName("NewMenuButton")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewMenuButton"); + entityExplorer.AssertEntityPresenceInExplorer("NewMenuButtonCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewMenuButtonCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewMenuButton"); + propPane.DeleteWidgetFromPropertyPane("NewMenuButtonCopy"); + entityExplorer.SelectEntityByName("NewMenuButton", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("3. Verify changing label text", () => { + propPane.UpdatePropertyFieldValue("Label", "Open Menu New"); + agHelper.AssertText(locators._buttonText, "text", "Open Menu New"); + }); + + it("4. Validating menu items", () => { + // Add Item + agHelper + .GetElementLength(locators._propertyControlInput("menuitems")) + .then((initialLength) => { + agHelper.GetNClick(propPane._addMenuItem); + agHelper + .GetElementLength(locators._propertyControlInput("menuitems")) + .then((finalLength) => { + expect(finalLength).to.be.eq(initialLength + 1); + }); + }); + + // Delete item + agHelper.GetNClick(table._deleteColumn, 3); + agHelper.AssertElementAbsence('[value="Menu Item 1"]'); + + // Open Item Settings + propPane.OpenTableColumnSettings("menuItem3"); + agHelper.AssertText( + `${propPane._paneTitle} span`, + "text", + "Third Menu Item", + ); + agHelper.GetNClick(propPane._goBackToProperty); + + // Update Item name + agHelper.ClearNType( + locators._propertyControlInput("menuitems"), + "First Menu Item New", + 0, + ); + agHelper.GetNClick(locators._widgetInDeployed("menubuttonwidget")); + agHelper.AssertElementExist( + buttongroupwidgetlocators.buttonMenuOptions("First Menu Item New"), + ); + }); + + it("5. Validate visible and disabled toggle", () => { + propPane.TogglePropertyState("visible", "Off"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("menubuttonwidget"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("menubuttonwidget"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMenuButton", "Widgets"); + propPane.TogglePropertyState("visible", "On"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("menubuttonwidget"), + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("menubuttonwidget"), + ); + deployMode.NavigateBacktoEditor(); + + // Visible JS mode + entityExplorer.SelectEntityByName("NewMenuButton", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "false"); + + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed("menubuttonwidget"), + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMenuButton", "Widgets"); + propPane.ToggleJSMode("Visible", true); + propPane.UpdatePropertyFieldValue("Visible", "true"); + propPane.ToggleJSMode("Visible", false); + + // Disabled + entityExplorer.SelectEntityByName("NewMenuButton", "Widgets"); + propPane.TogglePropertyState("disabled", "On"); + agHelper.AssertAttribute( + locators._widgetInDeployed("menubuttonwidget"), + "disabled", + "disabled", + ); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute( + locators._widgetInDeployed("menubuttonwidget"), + "disabled", + "disabled", + ); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute( + locators._widgetInDeployed("menubuttonwidget"), + "disabled", + "disabled", + ); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewMenuButton", "Widgets"); + propPane.TogglePropertyState("disabled", "Off"); + }); + + it("6. Validate compact toggle", () => { + propPane.TogglePropertyState("compact", "On"); + agHelper.GetNClick(locators._widgetInDeployed("menubuttonwidget")); + agHelper.AssertCSS(locators._menuItem, "padding-top", "3px"); + propPane.TogglePropertyState("compact", "Off"); + agHelper.AssertCSS(locators._menuItem, "padding-top", "9px"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/PhoneInput/PhoneInput_Part2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/PhoneInput/PhoneInput_Part2_spec.ts new file mode 100644 index 0000000000..abacbb5aa4 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/PhoneInput/PhoneInput_Part2_spec.ts @@ -0,0 +1,360 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Phone Input widget Tests", function () { + before(() => { + entityExplorer.DragDropWidgetNVerify("phoneinputwidget", 550, 100); + }); + + it("1. Verify property visibility", function () { + const dataProperties = [ + "defaultvalue", + "defaultcountrycode", + "changecountrycode", + ]; + + const labelProperties = ["text", "position"]; + + const validationsProperties = [ + "required", + "regex", + "valid", + "errormessage", + ]; + + const generalProperties = [ + "tooltip", + "placeholder", + "visible", + "disabled", + "animateloading", + "autofocus", + "enableformatting", + "height", + ]; + + const eventsProperties = [ + "ontextchanged", + "onfocus", + "onblur", + "onsubmit", + "resetonsubmit", + ]; + + const labelStylesProperties = ["fontcolor", "fontsize"]; + + const borderShadows = ["borderradius", "boxshadow"]; + + entityExplorer.SelectEntityByName("PhoneInput1", "Widgets"); + // Data section + dataProperties.forEach((dataSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("data", `${dataSectionProperty}`), + ); + }); + + // Label section + labelProperties.forEach((labelSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "label", + `${labelSectionProperty}`, + ), + ); + }); + + // Validation section + validationsProperties.forEach((validationSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "validation", + `${validationSectionProperty}`, + ), + ); + }); + + // General section + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + // Events section + eventsProperties.forEach((eventsSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "events", + `${eventsSectionProperty}`, + ), + ); + }); + + propPane.MoveToTab("Style"); + labelStylesProperties.forEach((labelStyleSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "labelstyles", + `${labelStyleSectionProperty}`, + ), + ); + }); + + borderShadows.forEach((borderShadowSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "borderandshadow", + `${borderShadowSectionProperty}`, + ), + ); + }); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer( + "PhoneInput1", + "NewPhoneInput", + true, + ); + agHelper.AssertElementVisibility(locators._widgetName("NewPhoneInput")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.CopyPasteWidget("NewPhoneInput"); + entityExplorer.AssertEntityPresenceInExplorer("NewPhoneInputCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewPhoneInputCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewPhoneInput"); + propPane.DeleteWidgetFromPropertyPane("NewPhoneInputCopy"); + entityExplorer.SelectEntityByName("NewPhoneInput", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("3. Verify tooltip", () => { + entityExplorer.DragDropWidgetNVerify("textwidget", 550, 300); + propPane.UpdatePropertyFieldValue("Text", "1000"); + entityExplorer.SelectEntityByName("NewPhoneInput", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "{{Text1.text}}"); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1000"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1000"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("1000"); + deployMode.NavigateBacktoEditor(); + }); + + it("4. Verify change country code toggle", () => { + entityExplorer.SelectEntityByName("NewPhoneInput", "Widgets"); + propPane.TogglePropertyState("changecountrycode", "On"); + agHelper.AssertElementVisibility(propPane._countryCodeChangeDropDown); + agHelper.GetNClick(propPane._countryCodeChangeDropDown); + agHelper.TypeText(propPane._searchCountryPlaceHolder, "India"); + agHelper.GetNAssertContains(locators._dropdownText, "India (+91)"); + agHelper.Sleep(2000); + agHelper.GetNClick("//span[text()='India (+91)']"); + }); + + it("5. Verify changing Label text and position", () => { + propPane.UpdatePropertyFieldValue("Text", "New Label"); + agHelper.AssertText(locators._label, "text", "New Label"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Left')`); + agHelper.AssertAttribute(locators._label, "position", "Left"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "position", "Left"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "position", "Left"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewPhoneInput", "Widgets"); + agHelper.GetNClick(`${locators._adsV2Text}:contains('Top')`); + agHelper.AssertAttribute(locators._label, "position", "Top"); + }); + + it("6. Verify validation Regex, valid criteria and error message", () => { + // Regex validation + propPane.UpdatePropertyFieldValue("Regex", "^\\d{1,3}$"); + propPane.UpdatePropertyFieldValue("Error message", "Not valid value"); + agHelper.ClearNType(locators._input, "1234"); + agHelper.AssertPopoverTooltip("Not valid value"); + agHelper.ClearNType(locators._input, "111"); + agHelper.AssertElementAbsence(locators._popoverToolTip); + propPane.RemoveText("Regex"); + + // Valid option + propPane.UpdatePropertyFieldValue("Valid", "{{Text1.isVisible}}"); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.TogglePropertyState("visible", "Off"); + agHelper.GetNClick(locators._input); + agHelper.AssertPopoverTooltip("Not valid value"); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.TogglePropertyState("visible", "On"); + agHelper.GetNClick(locators._input); + agHelper.AssertElementAbsence(locators._popoverToolTip); + }); + + it("7. Validate 'visible', 'disable' and 'auto Focus' toggle", () => { + // Verify Disabled toggle + propPane.TogglePropertyState("disabled", "On"); + agHelper.AssertAttribute( + locators._widgetInDeployed("phoneinputwidget"), + "disabled", + "disabled", + ); + propPane.TogglePropertyState("disabled", "Off"); + // Verify Visible toggle + propPane.TogglePropertyState("visible", "Off"); + agHelper.AssertAttribute( + locators._widgetInDeployed("phoneinputwidget"), + "data-hidden", + "true", + ); + agHelper.AssertExistingToggleState("visible", "false"); + propPane.TogglePropertyState("visible", "On"); + agHelper.AssertExistingToggleState("visible", "true"); + // Auto Focus + propPane.TogglePropertyState("autofocus", "On"); + agHelper.RefreshPage(); + agHelper.AssertElementFocus(locators._input); + }); + + it("8. Validate Enable formatting toggle", () => { + agHelper.GetNClick(propPane._countryCodeChangeDropDown); + agHelper.TypeText(propPane._searchCountryPlaceHolder, "India"); + agHelper.Sleep(2000); + agHelper.GetNClick("//span[text()='India (+91)']"); + agHelper.RemoveCharsNType(locators._input, -1, "9191919191"); + agHelper.AssertText(locators._input, "val", "91919 19191"); + propPane.TogglePropertyState("enableformatting", "Off"); + agHelper.AssertText(locators._input, "val", "9191919191"); + }); + + it("9. Validate auto height with limits", () => { + propPane.SelectPropertiesDropDown("height", "Auto Height with limits"); + agHelper.HoverElement(propPane._autoHeightLimitMin); + agHelper.AssertContains("Min-Height: 4 rows"); + agHelper.HoverElement(propPane._autoHeightLimitMax); + agHelper.AssertContains("Max-Height: 9 rows"); + propPane.SelectPropertiesDropDown("height", "Auto Height"); + }); + + it("10. Validate events onTextChange, onFocus, OnBlur and OnSubmit", () => { + // onSubmit + propPane.SelectPlatformFunction("onSubmit", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value Submitted", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.ClearNType(locators._input, "12345678"); + agHelper.GetElement(locators._input).type("{enter}"); + agHelper.ValidateToastMessage("Value Submitted"); + + // onTextChange + propPane.SelectPlatformFunction("onTextChanged", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value Changed", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.ClearNType(locators._input, "100"); + agHelper.ValidateToastMessage("Value Changed"); + + // onFocus + propPane.SelectPlatformFunction("onFocus", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value Focused", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.GetNClick(locators._input); + agHelper.ValidateToastMessage("Value Focused"); + + // OnBlur + propPane.SelectPlatformFunction("onBlur", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Blurred", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + + agHelper.GetNClick(locators._input); + agHelper.WaitUntilToastDisappear("Value Focused"); + agHelper.ClickOutside(); + agHelper.ValidateToastMessage("Blurred"); + }); + + it("11. Verify Full color picker and font size", () => { + // Verify font color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("fontcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("fontcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + // Font size + propPane.SelectPropertiesDropDown("fontsize", "L"); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "L"); + propPane.ToggleJSMode("fontsize", true); + propPane.UpdatePropertyFieldValue("Font size", "1rem"); + propPane.ToggleJSMode("fontsize", false); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "M"); + // Verify Emphasis + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.AssertAttribute(locators._label, "font-style", "BOLD"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + propPane.ToggleJSMode("emphasis", true); + propPane.UpdatePropertyFieldValue("Emphasis", "ITALIC"); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewPhoneInput", "Widgets"); + propPane.MoveToTab("Style"); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS(".text-input-wrapper", "border-radius", "0px"); + + // Verify Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + agHelper.AssertCSS( + ".text-input-wrapper", + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/RTE/RichTextEditor3_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/RTE/RichTextEditor3_spec.ts new file mode 100644 index 0000000000..5205cd5f93 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/RTE/RichTextEditor3_spec.ts @@ -0,0 +1,69 @@ +import { + agHelper, + locators, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Rich Text Editor widget Tests", function () { + before(() => { + agHelper.AddDsl("richTextEditorDsl"); + entityExplorer.SelectEntityByName("RichTextEditor1", "Widgets"); + // entityExplorer.DragDropWidgetNVerify("richtexteditorwidget", 500, 200); + }); + + it("1. Verify deleting text in default text property, updates data in widget", function () { + propPane.UpdatePropertyFieldValue("Default value", ""); + agHelper + .GetElement( + locators._widgetInDeployed("richtexteditorwidget") + " iframe", + ) + .then(($iframe) => { + const $body = $iframe.contents().find("body"); + expect($body).to.contain(""); + }); + }); + + it("2. Verify changing style to Heading and pressing enter should change style to paragraph", function () { + agHelper.GetNClick(locators._richText_TitleBlock); + agHelper.GetNClick(locators._richText_Heading); + agHelper.AssertText(locators._richText_Label_Text, "text", "Heading 1"); + agHelper + .GetElement( + locators._widgetInDeployed("richtexteditorwidget") + " iframe", + ) + .then(($iframe) => { + const $body = $iframe.contents().find("body"); + agHelper.TypeText($body, "Test Heading"); + agHelper.GetElement($body).type("{enter}"); + }); + agHelper.AssertText(locators._richText_Label_Text, "text", "Paragraph"); + }); + + it("3. Verify applying style in one line should be observed in next line", function () { + agHelper.GetNClick(locators._richText_Text_Color); + agHelper.GetNClick(locators._richText_color("Red")); + agHelper + .GetElement( + locators._widgetInDeployed("richtexteditorwidget") + " iframe", + ) + .then(($iframe) => { + const iframe = $iframe.contents(); + const $body = $iframe.contents().find("body"); + agHelper.TypeText($body, "Test Red"); + agHelper.GetElement($body).type("{enter}"); + agHelper.TypeText($body, "Test Red 2"); + }); + agHelper + .GetElement( + locators._widgetInDeployed("richtexteditorwidget") + " iframe", + ) + .then(($iframe) => { + const iframe = $iframe.contents(); + + const $span = iframe.find(locators._richText_line); + agHelper.AssertAttribute($span, "style", "color: rgb(224, 62, 45);", 0); + agHelper.AssertAttribute($span, "style", "color: rgb(224, 62, 45);", 1); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Radio/Radio2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Radio/Radio2_spec.ts new file mode 100644 index 0000000000..80ec9740b3 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Radio/Radio2_spec.ts @@ -0,0 +1,420 @@ +import { + agHelper, + apiPage, + dataManager, + deployMode, + draggableWidgets, + entityExplorer, + jsEditor, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Radio Widget test cases", function () { + it("1. Validate radio widget bindings", () => { + //JS Object + jsEditor.CreateJSObject( + `export default { + myFun1 () { + const myVar1= [{ + label:'test', + value:'test'}] + return myVar1 + } + }`, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + }, + ); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.RADIO_GROUP); + propPane.EnterJSContext("Options", "{{JSObject1.myFun1()}}"); + + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption("test"), + "false", + ); + deployMode.NavigateBacktoEditor(); + + //API + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, + ); + apiPage.RunAPI(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext( + "Options", + `{{Api1.data.map((s)=>{ + return {label: s.name, + value: s.name} + })}}`, + ); + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.GetElement("@postExecute").then((interception: any) => { + agHelper.Sleep(); + const name = interception.response.body.data.body[0].name; + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption(name), + "false", + ); + }); + agHelper.AssertElementLength(widgetLocators.radioBtn, 10); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + + //Array + propPane.EnterJSContext( + "Options", + `[{ + "label": "Blue", + "value": "BLUE" + }, + { + "label": "Green", + "value": "GREEN" + }]`, + ); + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption("Blue"), + "false", + ); + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption("Green"), + "false", + ); + }); + + it("2. Validate validation errors evaluated value poup", () => { + //String + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext("Options", "test"); + agHelper.VerifyEvaluatedErrorMessage( + `This value does not evaluate to type Array<{ "label": "string", "value": "string" | number }>`, + ); + + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.GetNAssertContains( + widgetLocators.radioWidgetContainer, + "test", + "not.exist", + ); + + //Non array + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext("Options", `[{name:1,class:10}]`); + agHelper.VerifyEvaluatedErrorMessage( + `This value does not evaluate to type Array<{ "label": "string", "value": "string" | number }>`, + ); + + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.GetNAssertContains( + widgetLocators.radioWidgetContainer, + "10", + "not.exist", + ); + + //Non array api data + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext( + "Options", + `{{Api1.data.map((s)=>{ + return value: s.name + }})}`, + ); + agHelper.VerifyEvaluatedErrorMessage( + `This value does not evaluate to type Array<{ "label": "string", "value": "string" | number }>`, + ); + + //Non array JS data + jsEditor.CreateJSObject( + `export default { + myFun1 () { + const myVar1= { + label:'test', + value:'test'} + return myVar1 + } + }`, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + }, + ); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext("Options", `"{{JSObject2.myFun1()}}"`); + agHelper.VerifyEvaluatedErrorMessage( + `This value does not evaluate to type Array<{ "label": "string", "value": "string" | number }>`, + ); + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.GetNAssertContains( + widgetLocators.radioWidgetContainer, + "test", + "not.exist", + ); + }); + + it("3. Verify default selected value property", () => { + //String + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext( + "Options", + `[{ + "label": "Blue", + "value": "BLUE" + }, + { + "label": "Green", + "value": "GREEN" + }]`, + ); + propPane.UpdatePropertyFieldValue("Default selected value", "red"); + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption("Blue"), + "false", + ); + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption("Green"), + "false", + ); + + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext("Options", "{{JSObject1.myFun1()}}"); + propPane.UpdatePropertyFieldValue( + "Default selected value", + "{{JSObject1.myFun1()[0]}}", + ); + agHelper.VerifyEvaluatedErrorMessage( + "This value does not evaluate to type: string or number", + ); + + propPane.UpdatePropertyFieldValue( + "Default selected value", + "{{JSObject1.myFun1()[0].label}}", + ); + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.AssertExistingCheckedState(locators._checkboxTypeByOption("test")); + }); + + it("4. Validate Label properties - Text , Position , Alignment , Width(in columns)", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + //Text + propPane.TypeTextIntoField("Text", "Select Value"); + + //Position + agHelper.AssertAttribute( + locators._position("Top"), + "data-selected", + "true", + ); + agHelper.AssertCSS(widgetLocators.radioWidgetLabel, "margin-bottom", "5px"); + agHelper.AssertCSS(widgetLocators.radioWidgetLabel, "margin-right", "0px"); + agHelper.GetNClick(locators._position("Left")); + + //Alignment + agHelper.AssertAttribute( + locators._alignment("left"), + "data-selected", + "true", + ); + agHelper.GetNClick(locators._alignment("right")); + + //Width + agHelper.AssertCSS( + widgetLocators.radioWidgetLabelContainer, + "width", + "59.765625px", + ); + agHelper.GetNClick(widgetLocators.selectWidgetWidthPlusBtn); + agHelper.GetNClick(widgetLocators.selectWidgetWidthPlusBtn); + + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.AssertCSS(widgetLocators.radioWidgetLabel, "margin-bottom", "0px"); + agHelper.AssertCSS(widgetLocators.radioWidgetLabel, "margin-right", "5px"); + agHelper.AssertCSS(widgetLocators.radioWidgetLabel, "text-align", "right"); + agHelper.AssertCSS( + widgetLocators.radioWidgetLabelContainer, + "width", + "151.265625px", + ); + agHelper.AssertText( + widgetLocators.radioWidgetLabel, + "text", + "Select Value", + ); + }); + + it("5. Validate general section in radio group", function () { + deployMode.NavigateBacktoEditor(); + + //Tooltip + entityExplorer.DragNDropWidget(draggableWidgets.TEXT, 300, 300); + propPane.UpdatePropertyFieldValue("Text", "Tooltip text"); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext( + "Options", + `{{Api1.data.map((s)=>{ + return {label: s.name, + value: s.name} + })}}`, + ); + propPane.UpdatePropertyFieldValue("Tooltip", "{{Text1.text}}"); + agHelper.AssertExistingToggleState("Disabled", "false"); + agHelper.AssertExistingToggleState("Inline", "true"); + agHelper.AssertExistingToggleState("Visible", "true"); + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.Sleep(2000); //for Radio Group to load fully, for CI flakyness + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("Tooltip text"); + agHelper.AssertElementEnabledDisabled( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + 0, + false, + ); + agHelper.GetNClick( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + + agHelper.GetHeight( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + cy.get("@eleHeight").then(($currentHeight: any) => { + expect($currentHeight).to.be.greaterThan(130); + }); + + agHelper.GetWidth(locators._widgetInDeployed(draggableWidgets.RADIO_GROUP)); + agHelper.GetElement("@eleWidth").then(($currentWidth) => { + expect($currentWidth).to.be.greaterThan(420); + }); + }); + + it("6. Validate general section in radio group - Part2", function () { + //Disable - should throw error for non boolean values + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext("Disabled", "test", true, true); + agHelper.VerifyEvaluatedErrorMessage( + `This value does not evaluate to type boolean`, + ); + propPane.EnterJSContext("Disabled", "{{!!(Text1.text)}}", true, true); + + //Inline - should throw error for non boolean values + propPane.EnterJSContext("Inline", "test", true, true); + agHelper.VerifyEvaluatedErrorMessage( + `This value does not evaluate to type boolean`, + ); + propPane.EnterJSContext("Inline", "{{Text1.text}}", true, true); + + //Visible - should throw error for non boolean values + propPane.EnterJSContext("Visible", "test", true, true); + agHelper.VerifyEvaluatedErrorMessage( + `This value does not evaluate to type boolean`, + ); + propPane.EnterJSContext("Visible", "{{!!(Text1.text)}}", true, true); + + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.UpdatePropertyFieldValue("Text", "false"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper.Sleep(2000); //for Radio Group to load fully, for CI flakyness + agHelper.WaitUntilEleAppear( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + agHelper.AssertElementEnabledDisabled( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + 0, + true, + ); + agHelper.GetHeight( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + cy.get("@eleHeight").then(($currentHeight: any) => { + expect($currentHeight).to.be.greaterThan(270); + }); + + agHelper.GetWidth(locators._widgetInDeployed(draggableWidgets.RADIO_GROUP)); + agHelper.GetElement("@eleWidth").then(($currentWidth) => { + expect($currentWidth).to.be.greaterThan(420); + }); + }); + + it("7. Validate set property methods for Radio group", () => { + deployMode.NavigateBacktoEditor(); + //JS Object + jsEditor.CreateJSObject( + `export default { + myVar1: [{ + label:'test', + value:'test'}], + myFun1 () { + RadioGroup1.setData(this.myVar1); + RadioGroup1.isVisible? RadioGroup1.setDisabled(true):RadioGroup1.setVisibility(false) + } + }`, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + }, + ); + entityExplorer.SelectEntityByName("RadioGroup1", "Widgets"); + propPane.EnterJSContext("Disabled", "false", true, true); + propPane.EnterJSContext("onSelectionChange", "{{JSObject3.myFun1();}}"); + + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + ); + + agHelper.GetElement("@postExecute").then((interception: any) => { + agHelper.Sleep(); + const name = interception.response.body.data.body[0].name; + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption(name), + "false", + ); + }); + agHelper.GetNClick(widgetLocators.radioBtn, 1); + agHelper.AssertExistingCheckedState( + locators._checkboxTypeByOption("test"), + "false", + ); + agHelper.AssertElementEnabledDisabled( + locators._widgetInDeployed(draggableWidgets.RADIO_GROUP), + 0, + true, + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Rating/Rating_Widget_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Rating/Rating_Widget_spec.ts index 88e27f6fdf..625d133a8d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Rating/Rating_Widget_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Rating/Rating_Widget_spec.ts @@ -137,7 +137,7 @@ describe("Rating widet testcases", () => { deployMode.NavigateBacktoEditor(); agHelper.GetNClick(RATING_WIDGET.ratingwidget); // open a modal on clicking ratings - propPane.CreateModal("Thanks for rating us!", "onChange"); + propPane.CreateModal("onChange"); // deploy app and click on stars and close the modal deployMode.DeployApp(); agHelper.GetNClick(RATING_WIDGET.star_icon, 5, true, 0); @@ -153,13 +153,5 @@ describe("Rating widet testcases", () => { // copy widget from property pane and assert copied info propPane.CopyPasteWidgetFromPropertyPane("RateUs"); agHelper.ValidateToastMessage("Copied RateUs"); - // copy widget using keyboard and assert copied info - entityExplorer.CopyPasteWidget("RateUs"); - agHelper.ValidateToastMessage("Copied RateUs"); - agHelper.AssertText(RATING_WIDGET.ratingWidgetName, "text", "RateUsCopy1"); - // delete both widgets - propPane.DeleteWidgetFromPropertyPane("RateUsCopy"); - propPane.DeleteWidgetFromPropertyPane("RateUs"); - agHelper.AssertElementAbsence(RATING_WIDGET.ratingwidget); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/RTL_support.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/RTL_support.ts new file mode 100644 index 0000000000..eaa7d7e1c2 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/RTL_support.ts @@ -0,0 +1,65 @@ +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; +import { + agHelper, + draggableWidgets, + entityExplorer, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Select Widget", () => { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.SELECT); + }); + + it("1. Test RTL support", () => { + featureFlagIntercept({ + license_widget_rtl_support_enabled: false, + }); + agHelper.AssertElementAbsence(".t--property-control-enablertl"); + featureFlagIntercept({ + license_widget_rtl_support_enabled: true, + }); + + agHelper.Sleep(2000); + + agHelper.AssertElementExist(".t--property-control-enablertl"); + + propPane.TogglePropertyState("Enable RTL", "On"); + + agHelper.GetElement(".t--widget-selectwidget .select-button").click(); + + agHelper + .GetElement(".t--widget-selectwidget .label-container") + .should("have.css", "direction", "rtl"); + + agHelper + .GetElement(".t--widget-selectwidget .select-button") + .should("have.css", "direction", "rtl"); + + agHelper + .GetElement(".select-popover-wrapper input.bp3-input") + .should("have.css", "direction", "rtl"); + + agHelper + .GetElement(".select-popover-wrapper .menu-virtual-list") + .should("have.css", "direction", "rtl"); + + propPane.TogglePropertyState("Enable RTL", "Off"); + + agHelper + .GetElement(".t--widget-selectwidget .label-container") + .should("have.css", "direction", "ltr"); + + agHelper + .GetElement(".t--widget-selectwidget .select-button") + .should("have.css", "direction", "ltr"); + + agHelper + .GetElement(".select-popover-wrapper input.bp3-input") + .should("have.css", "direction", "ltr"); + + agHelper + .GetElement(".select-popover-wrapper .menu-virtual-list") + .should("have.css", "direction", "ltr"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select2_Spec.ts new file mode 100644 index 0000000000..a589a0374a --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select2_Spec.ts @@ -0,0 +1,287 @@ +import { getWidgetSelector } from "../../../../../locators/WidgetLocators"; +import { + agHelper, + draggableWidgets, + deployMode, + entityExplorer, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Select widget tests", function () { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.SELECT); + }); + + it("1. Validate Label properties - Text , Position , Alignment , Width(in columns)", function () { + //Text + propPane.TypeTextIntoField("Text", "Select Value"); + + //Position + agHelper.AssertAttribute( + locators._position("Top"), + "data-selected", + "true", + ); + agHelper.AssertCSS( + widgetLocators.selectWidgetLabel, + "margin-bottom", + "5px", + ); + agHelper.AssertCSS(widgetLocators.selectWidgetLabel, "margin-right", "0px"); + agHelper.GetNClick(locators._position("Left")); + + //Alignment + agHelper.AssertAttribute( + locators._alignment("left"), + "data-selected", + "true", + ); + agHelper.GetNClick(locators._alignment("right")); + + //Width + agHelper.AssertCSS( + widgetLocators.selectWidgetLabelContainer, + "width", + "59.765625px", + ); + agHelper.GetNClick(widgetLocators.selectWidgetWidthPlusBtn); + agHelper.GetNClick(widgetLocators.selectWidgetWidthPlusBtn); + + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper.AssertCSS( + widgetLocators.selectWidgetLabel, + "margin-bottom", + "0px", + ); + agHelper.AssertCSS(widgetLocators.selectWidgetLabel, "margin-right", "5px"); + agHelper.AssertCSS(widgetLocators.selectWidgetLabel, "text-align", "right"); + agHelper.AssertCSS( + widgetLocators.selectWidgetLabelContainer, + "width", + "129.65625px", + ); + agHelper.AssertText( + widgetLocators.selectWidgetLabel, + "text", + "Select Value", + ); + }); + + it("2. When user selects another option the previous selected option is removed and update with current selection", function () { + agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + expect($selectedValue).to.eq("Green"); + }); + agHelper.SelectDropDown("Blue"); + agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + expect($selectedValue).to.eq("Blue"); + expect($selectedValue).not.to.contain("Green"); + }); + }); + + it("3. Validate tooltip and placeholder", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.UpdatePropertyFieldValue("Tooltip", "{{Input1.text}}"); + propPane.UpdatePropertyFieldValue("Placeholder", "{{Input1.text}}"); + entityExplorer.DragNDropWidget(draggableWidgets.INPUT_V2, 300, 200); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.INPUT_V2)); + agHelper.TypeText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "Input text", + ); + agHelper.GetNClick(widgetLocators.selectWidgetClear); + agHelper.AssertContains( + "Input text", + "be.visible", + widgetLocators.selectWidgetBtn, + ); + agHelper.HoverElement(locators._tooltipIcon); + agHelper.AssertPopoverTooltip("Input text"); + }); + + it("4. Verify Visible property", () => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + agHelper.AssertExistingToggleState("Visible", "true"); + propPane.EnterJSContext("Visible", "{{(55>45)?false:true}}", true, true); + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.SELECT), + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.EnterJSContext("Visible", "", false); + propPane.ToggleJSMode("Visible", false); + propPane.TogglePropertyState("Visible", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.SELECT), + ); + }); + + it("5. Verify Disabled property", () => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + agHelper.AssertExistingToggleState("Disabled", "false"); + propPane.EnterJSContext("Disabled", "{{(45>55)?false:true}}", true, true); + deployMode.DeployApp(); + agHelper.AssertElementEnabledDisabled( + widgetLocators.selectWidgetBtn, + 0, + true, + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.EnterJSContext("Disabled", "", false); + propPane.ToggleJSMode("Disabled", false); + propPane.TogglePropertyState("Disabled", "Off"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper + .GetElement(widgetLocators.selectWidgetBtn) + .should("not.have.attr", "disabled"); + }); + + it("6. Verify Height property", () => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.AssertPropertiesDropDownCurrentValue("Height", "Fixed"); + propPane.AssertPropertiesDropDownValues("Height", [ + "Auto Height", + "Auto Height with limits", + "Fixed", + ]); + propPane.SelectPropertiesDropDown("Height", "Auto Height"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper.AssertCSS( + getWidgetSelector(draggableWidgets.SELECT), + "height", + "40px", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.SelectPropertiesDropDown("Height", "Auto Height with limits"); + agHelper.AssertElementVisibility(locators._autoHeightHandles); + agHelper.AssertElementVisibility(locators._autoHeightMin); + agHelper.AssertElementVisibility(locators._autoHeightMax); + propPane.SelectPropertiesDropDown("Height", "Fixed"); + }); + + it("7. Validate OnOptionChange , OnDropdownOpen , OnDropdownClose events are JS convertible", () => { + propPane.EnterJSContext( + "onOptionChange", + "{{showAlert('Option changed!','success')}}", + true, + ); + propPane.ToggleJSMode("onOptionChange", false); + propPane.EnterJSContext( + "onDropdownOpen", + "{{showAlert('Dropdown opened!','success')}}", + true, + ); + propPane.ToggleJSMode("onDropdownOpen", false); + propPane.EnterJSContext( + "onDropdownClose", + "{{showAlert('Dropdown closed!','success')}}", + true, + ); + propPane.ToggleJSMode("onDropdownClose", false); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper.ValidateToastMessage("Dropdown opened!"); + agHelper.AssertElementVisibility(locators._selectOptionValue("Red"), true); + agHelper.GetNClick(locators._selectOptionValue("Red")); + agHelper.ValidateToastMessage("Dropdown closed!"); + agHelper.ValidateToastMessage("Option changed!"); + }); + + it("8. Verify select widget styles", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.SelectColorFromColorPicker("fontcolor", 9); + propPane.SelectPropertiesDropDown("Font size", "M"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.ContainsNClick("Medium"); + agHelper.GetNClick(locators._borderRadius("1.5rem")); + agHelper + .GetWidgetCSSFrAttribute(widgetLocators.selectWidgetLabel, "color") + .then((color) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.SELECT), + ); + agHelper.AssertCSS(widgetLocators.selectWidgetLabel, "color", color); + agHelper.AssertCSS( + widgetLocators.selectWidgetLabel, + "font-size", + "16px", + ); + agHelper.AssertCSS( + widgetLocators.selectWidgetLabel, + "font-weight", + "700", + ); + }); + agHelper.AssertCSS( + widgetLocators.selectWidgetBtn, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px", + ); + agHelper.AssertCSS(widgetLocators.selectWidgetBtn, "border-radius", "24px"); + + //JS conversion + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Font color", "#22c55e"); + propPane.EnterJSContext("Font size", "1.25rem"); + agHelper.GetNClick(propPane._emphasisSelector("ITALIC")); + propPane.EnterJSContext("Border radius", "1rem"); + propPane.EnterJSContext( + "Box shadow", + "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)", + ); + agHelper + .GetWidgetCSSFrAttribute(widgetLocators.selectWidgetLabel, "color") + .then((color) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.SELECT), + ); + agHelper.AssertCSS(widgetLocators.selectWidgetLabel, "color", color); + agHelper.AssertCSS( + widgetLocators.selectWidgetLabel, + "font-size", + "20px", + ); + agHelper.AssertCSS( + widgetLocators.selectWidgetLabel, + "font-style", + "italic", + ); + }); + agHelper.AssertCSS( + widgetLocators.selectWidgetBtn, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px", + ); + agHelper.AssertCSS(widgetLocators.selectWidgetBtn, "border-radius", "16px"); + }); + + it("9. Validate Validation required property", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.DragNDropWidget(draggableWidgets.FORM, 300, 400); + entityExplorer.DragNDropWidget(draggableWidgets.SELECT, 200, 500); + entityExplorer.SelectEntityByName("Select2", "Widgets"); + agHelper.AssertExistingToggleState("Required", "false"); + propPane.TogglePropertyState("Required", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.FORM)); + agHelper.GetNClick(widgetLocators.selectWidgetClear, 1); + agHelper.AssertCSS( + widgetLocators.selectWidgetBtn, + "border-color", + "rgb(217, 25, 33)", + 1, + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select3_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select3_Spec.ts new file mode 100644 index 0000000000..52ad40d03c --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select3_Spec.ts @@ -0,0 +1,139 @@ +import { + agHelper, + dataSources, + draggableWidgets, + deployMode, + entityExplorer, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Select widget tests", function () { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.SELECT); + }); + + it("1. Validate Server side filtering", () => { + //Create postgres datasource + dataSources.CreateDataSource("Postgres"); + dataSources.CreateQueryAfterDSSaved( + "SELECT * FROM public.astronauts {{this.params.filterText ? `WHERE name LIKE '%${this.params.filterText}%'` : ''}} LIMIT 10;", + ); + dataSources.ToggleUsePreparedStatement(false); + dataSources.RunQuery(); + + //Bind it to select widget + entityExplorer.SelectEntityByName("Select1", "Widgets"); + propPane.TogglePropertyState("Server side filtering", "On"); + propPane.ToggleJSMode("Server side filtering", true); + propPane + .EvaluateExistingPropertyFieldValue("Server side filtering") + .then((val: any) => { + expect(val).to.eq("true"); + }); + propPane.ToggleJSMode("Server side filtering", false); + propPane.EnterJSContext( + "Source Data", + ` + {{Query1.data.map((d) => ({ + name: d.name, + code: d.name + }))}} + `, + true, + ); + propPane.EnterJSContext( + "onFilterUpdate", + ` + {{Query1.run({filterText: Select1.filterText})}} +`, + true, + ); + propPane.ToggleJSMode("onFilterUpdate", false); + propPane.SelectPlatformFunction("onFilterUpdate", "Show alert"); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Value changed!", + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + + //Validate filtered data + agHelper.Sleep(3000); //Wait for widget to settle + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper.TypeText(widgetLocators.selectWidgetFilter, "Ulf"); + agHelper.Sleep(3000); //Wait for widget filter to settle for CI runs + agHelper.AssertElementVisibility( + locators._selectOptionValue("Ulf Merbold"), + true, + ); + agHelper.GetNClick(locators._selectOptionValue("Ulf Merbold"), 0, true); + agHelper.Sleep(); //for the new value to be set + agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + expect($selectedValue).to.eq("Ulf Merbold"); + }); + }); + + it("2. Validate renaming, duplication(copy, paste) & deletion of select widget", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Select1", "Widgets"); + //Rename widget + propPane.RenameWidget("Select1", "Select_Widget"); + agHelper.AssertContains( + "Select_Widget", + "be.visible", + widgetLocators.widgetNameTag, + ); + agHelper.GetNClick(locators._widgetInCanvas(draggableWidgets.SELECT)); + + //Duplicate with hotkeys + entityExplorer.CopyPasteWidget("Select_Widget"); + agHelper.ValidateToastMessage("Copied Select_Widget"); + agHelper.AssertContains( + "Select_WidgetCopy", + "be.visible", + widgetLocators.widgetNameTag, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.SELECT)) + .should("have.length", 2); + deployMode.NavigateBacktoEditor(); + + //Duplicate from property pane + entityExplorer.SelectEntityByName("Select_WidgetCopy", "Widgets"); + propPane.CopyPasteWidgetFromPropertyPane("Select_WidgetCopy"); + agHelper.ValidateToastMessage("Copied Select_WidgetCopy"); + agHelper.AssertContains( + "Select_WidgetCopyCopy", + "be.visible", + widgetLocators.widgetNameTag, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.SELECT)) + .should("have.length", 3); + deployMode.NavigateBacktoEditor(); + + //Delete widget from property pane + propPane.DeleteWidgetFromPropertyPane("Select_WidgetCopyCopy"); + + //Delete widget using hotkeys + entityExplorer.SelectEntityByName("Select_WidgetCopy", "Widgets"); + agHelper.PressDelete(); + agHelper.AssertContains( + "Select_WidgetCopyCopy", + "not.exist", + widgetLocators.widgetNameTag, + ); + agHelper.AssertContains( + "Select_WidgetCopy", + "not.exist", + widgetLocators.widgetNameTag, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.SELECT)); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.SELECT)) + .should("have.length", 1); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js index a4a1a7e706..0aa0664347 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js @@ -29,5 +29,74 @@ describe("Select Widget Functionality", function () { "contain.text", "Green", ); + _.deployMode.NavigateBacktoEditor(); + }); + + it("2. Shows validation error for invalid defaultSelectedValue", () => { + const { agHelper, entityExplorer, locators, propPane } = _; + + entityExplorer.SelectEntityByName("SelectRenamed", "Widgets"); + + propPane.UpdatePropertyFieldValue("Default selected value", "GREEN1", true); + + agHelper.VerifyEvaluatedErrorMessage( + "Default value is missing in options. Please update the value.", + ); + + propPane.ToggleJSMode("Source Data", true); + + // Updates the options and asserts that the validation error is fixed + propPane.UpdatePropertyFieldValue( + "Source Data", + '[{"name": "Green", "code":"GREEN1"}]', + true, + ); + + agHelper.FocusElement( + locators._propertyInputField("Default selected value"), + ); + + agHelper.AssertElementAbsence(locators._evaluatedErrorMessage); + + // Changes options to bring back validation error + propPane.UpdatePropertyFieldValue( + "Source Data", + '[{"name": "Green", "code":"GREEN"}]', + true, + ); + + agHelper.FocusElement( + locators._propertyInputField("Default selected value"), + ); + + agHelper.VerifyEvaluatedErrorMessage( + "Default value is missing in options. Please update the value.", + ); + + // Reload to check if the error persists + agHelper.RefreshPage(); + + entityExplorer.SelectEntityByName("SelectRenamed", "Widgets"); + + agHelper.FocusElement( + locators._propertyInputField("Default selected value"), + ); + + agHelper.VerifyEvaluatedErrorMessage( + "Default value is missing in options. Please update the value.", + ); + + // Fixes the validation error + propPane.UpdatePropertyFieldValue( + "Source Data", + '[{"name": "Green", "code": {{"GREEN1"}}}]', + true, + ); + + agHelper.FocusElement( + locators._propertyInputField("Default selected value"), + ); + + agHelper.AssertElementAbsence(locators._evaluatedErrorMessage); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_label_value.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_label_value.ts index bdeb3cb1b4..24da11b70f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_label_value.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_label_value.ts @@ -1,24 +1,23 @@ -import * as _ from "../../../../../support/Objects/ObjectsCore"; -const explorer = require("../../../../../locators/explorerlocators.json"); -const widgetsPage = require("../../../../../locators/Widgets.json"); -const commonlocators = require("../../../../../locators/commonlocators.json"); -const formWidgetsPage = require("../../../../../locators/FormWidgets.json"); +import { + agHelper, + draggableWidgets, + entityExplorer, + locators, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; describe("Select Widget Functionality", function () { - before(() => { - _.agHelper.AddDsl("emptyDSL"); - }); - beforeEach(() => { - cy.wait(2000); - }); - it("Add new Select widget", () => { - _.agHelper.GetNClick(explorer.addWidget); - _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.SELECT, 450, 200); - _.agHelper.AssertElementExist(".t--widget-selectwidget"); - - _.propPane.ToggleJSMode("sourcedata"); - - _.propPane.UpdatePropertyFieldValue( + it("Validate select widget data - source data , label key , value key, default selected value ", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 450, 200); + agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + expect($selectedValue).to.eq("Green"); + }); + propPane.UpdatePropertyFieldValue("Default selected value", "BLUE"); + agHelper.ReadSelectedDropDownValue().then(($selectedValue) => { + expect($selectedValue).to.eq("Blue"); + expect($selectedValue).not.to.contain("Green"); + }); + propPane.EnterJSContext( "Source Data", `[ { @@ -35,19 +34,13 @@ describe("Select Widget Functionality", function () { "3": "red" } ]`, + true, ); + propPane.AssertPropertiesDropDownValues("Label key", ["1", "2", "3"]); - _.agHelper.GetNClick(_.propPane._selectPropDropdown("labelkey")); - ["1", "2", "3"].forEach((d) => { - _.agHelper.AssertElementExist(_.propPane._dropDownValue(d)); - }); + propPane.AssertPropertiesDropDownValues("Value key", ["1", "2", "3"]); - _.agHelper.GetNClick(_.propPane._selectPropDropdown("valuekey"), 0, true); - ["1", "2", "3"].forEach((d) => { - _.agHelper.AssertElementExist(_.propPane._dropDownValue(d)); - }); - - _.propPane.UpdatePropertyFieldValue( + propPane.UpdatePropertyFieldValue( "Source Data", `[ { @@ -64,24 +57,17 @@ describe("Select Widget Functionality", function () { } ]`, ); + propPane.AssertPropertiesDropDownValues("Label key", ["test1", "test2"]); - _.agHelper.GetNClick(_.propPane._selectPropDropdown("label")); - ["test1", "test2"].forEach((d) => { - _.agHelper.AssertElementExist(_.propPane._dropDownValue(d)); - }); + propPane.AssertPropertiesDropDownValues("Value key", ["test1", "test2"]); - _.agHelper.GetNClick(_.propPane._selectPropDropdown("value"), 0, true); - ["test1", "test2"].forEach((d) => { - _.agHelper.AssertElementExist(_.propPane._dropDownValue(d)); - }); + propPane.SelectPropertiesDropDown("label", "test1"); - _.propPane.SelectPropertiesDropDown("label", "test1"); + propPane.SelectPropertiesDropDown("value", "test2", "Action", 0, 1); - _.propPane.SelectPropertiesDropDown("value", "test2", "Action", 0, 1); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 450, 500); - _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 450, 500); - - _.propPane.UpdatePropertyFieldValue( + propPane.UpdatePropertyFieldValue( "Text", `{{Select1.selectedOptionLabel}}:{{Select1.selectedOptionValue}}`, ); @@ -100,30 +86,15 @@ describe("Select Widget Functionality", function () { text: "label3:value3", }, ].forEach((d) => { - cy.get(formWidgetsPage.selectWidget) - .find(widgetsPage.dropdownSingleSelect) - .click({ - force: true, - }); - - // confirm it only has a single child - cy.get(".select-popover-wrapper .menu-item-link") - .children() - .should("have.length", 3); - - cy.get(commonlocators.singleSelectWidgetMenuItem) - .contains(d.label) - .click({ - force: true, - }); - cy.get(commonlocators.TextInside).first().should("have.text", d.text); + agHelper.SelectDropDown(d.label); + agHelper.AssertText(locators._textInside, "text", d.text); }); - (cy as any).openPropertyPane("selectwidget"); + entityExplorer.SelectEntityByName("Select1"); - _.propPane.SelectPropertiesDropDown("label", "test2"); + propPane.SelectPropertiesDropDown("label", "test2"); - _.propPane.SelectPropertiesDropDown("value", "test1", "Action", 0, 1); + propPane.SelectPropertiesDropDown("value", "test1", "Action", 0, 1); [ { @@ -139,23 +110,8 @@ describe("Select Widget Functionality", function () { text: "value3:label3", }, ].forEach((d) => { - cy.get(formWidgetsPage.selectWidget) - .find(widgetsPage.dropdownSingleSelect) - .click({ - force: true, - }); - - // confirm it only has a single child - cy.get(".select-popover-wrapper .menu-item-link") - .children() - .should("have.length", 3); - - cy.get(commonlocators.singleSelectWidgetMenuItem) - .contains(d.label) - .click({ - force: true, - }); - cy.get(commonlocators.TextInside).first().should("have.text", d.text); + agHelper.SelectDropDown(d.label); + agHelper.AssertText(locators._textInside, "text", d.text); }); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js index 27f09fe84f..fbf478dc35 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js @@ -53,36 +53,4 @@ describe("Select Widget Functionality", function () { defaultValue, ); }); - - it("Copy and paste select widget", () => { - cy.openPropertyPane("selectwidget"); - const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; - //copy and paste - cy.openPropertyPane("selectwidget"); - cy.get("body").type(`{${modifierKey}}c`); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(500); - cy.get("body").click(); - cy.get("body").type(`{${modifierKey}}v`, { force: true }); - cy.wait("@updateLayout").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); - cy.get(widgetsPage.selectwidget).should("have.length", 2); - - cy.get(".t--property-control-defaultselectedvalue") - .first() - .click({ force: true }) - .find(".CodeMirror") - .first() - .then((ins) => { - const input = ins[0].CodeMirror; - let val = input.getValue(); - try { - val = JSON.parse(val); - expect(val).to.deep.equal(JSON.parse(defaultValue)); - } catch (error) {} - }); - }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/CategorySlider_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/CategorySlider_spec.ts index 1cbcf7b6fa..8654767e5b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/CategorySlider_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/CategorySlider_spec.ts @@ -169,8 +169,10 @@ describe("Category Slider spec", () => { agHelper.RemoveCharsNType(propPane._placeholderValue, -1, "xxl", 5); // Verify option added agHelper.AssertElementLength(propPane._placeholderName, len + 1); + agHelper.Sleep(); // Wait for the element to settle to delete it // Delete option - agHelper.GetNClick(propPane._optionsDeleteButton, 5); + agHelper.GetNClick(propPane._optionsDeleteButton, 5, true); + agHelper.Sleep(); // Wait for the element to be deleted // Verify option deleted agHelper.AssertElementLength(propPane._placeholderName, len); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/NumberSlider_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/NumberSlider_spec.ts index 19d23fd290..839872904e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/NumberSlider_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Sliders/NumberSlider_spec.ts @@ -425,7 +425,7 @@ describe("Number Slider spec", () => { .type("{rightArrow}") .type("{upArrow}"); - agHelper.Sleep(200); + agHelper.Sleep(); agHelper .GetText(getWidgetSelector(draggableWidgets.TEXT)) diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Statbox/Statbox_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Statbox/Statbox_spec.ts new file mode 100644 index 0000000000..b290103eb5 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Statbox/Statbox_spec.ts @@ -0,0 +1,147 @@ +import { getWidgetSelector } from "../../../../../locators/WidgetLocators"; +import { + agHelper, + appSettings, + assertHelper, + draggableWidgets, + entityExplorer, + locators, + deployMode, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Statbox spec", () => { + before(() => { + /** + * On the canvas we have a Statbox Widget + */ + entityExplorer.DragDropWidgetNVerify(draggableWidgets.STATBOX, 329, 124); + }); + + it("1. Validate all the respective properties are present on the Content and Style sections in the property pane", () => { + const generalProperties = ["visible", "animateloading", "height"]; + + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + // Switch to the Style Tab + propPane.MoveToTab("Style"); + + const colorProperties = ["backgroundcolor", "bordercolor"]; + colorProperties.forEach((labelStyleSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "color", + `${labelStyleSectionProperty}`, + ), + ); + }); + + const borderShadows = ["borderwidth", "borderradius", "boxshadow"]; + borderShadows.forEach((borderShadowSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "borderandshadow", + `${borderShadowSectionProperty}`, + ), + ); + }); + }); + it("2. Validate if the default widgets are present inside the statbox", () => { + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.AssertEntityPresenceInExplorer("Statbox1"); + entityExplorer.ExpandCollapseEntity("Statbox1"); + entityExplorer.AssertEntityPresenceInExplorer("Text1"); + entityExplorer.AssertEntityPresenceInExplorer("Text2"); + entityExplorer.AssertEntityPresenceInExplorer("IconButton1"); + entityExplorer.AssertEntityPresenceInExplorer("Text3"); + }); + it("3. Validate visibility", () => { + propPane.MoveToTab("Content"); + propPane.TogglePropertyState("Visible", "Off"); + // Ensure that the widget isnt visible once deployed + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._widgetInDeployed("statbox1")); + deployMode.NavigateBacktoEditor(); + //Ensure that the widget is not visible in preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence(locators._widgetInDeployed("statbox1")); + agHelper.GetNClick(locators._exitPreviewMode); + entityExplorer.SelectEntityByName("Statbox1", "Widgets"); + propPane.TogglePropertyState("Visible", "On"); + //Ensure that the widget is visible once deployed + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("statbox1"), + true, + ); + deployMode.NavigateBacktoEditor(); + //Ensure that the widget is visible in preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("statbox1"), + true, + ); + agHelper.GetNClick(locators._exitPreviewMode); + }); + + it("4. Validate if widgets can be D&D inside the Statbox widget", () => { + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.ExpandCollapseEntity("Statbox1"); + propPane.DeleteWidgetFromPropertyPane("IconButton1"); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.ICONBUTTON, 260, 189); + //Verifying if the dropped widget exists in the container + entityExplorer.NavigateToSwitcher("Explorer"); + entityExplorer.ExpandCollapseEntity("Statbox1"); + entityExplorer.AssertEntityPresenceInExplorer("IconButton1"); + //Verifying if the dropped widget exists once deployed + deployMode.DeployApp(); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("iconbutton1"), + true, + ); + deployMode.NavigateBacktoEditor(); + //Verifying if the dropped widget exists in preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility( + locators._widgetInDeployed("iconbutton1"), + true, + ); + agHelper.GetNClick(locators._exitPreviewMode); + }); + + it("5: Verify statbox widget styles", () => { + entityExplorer.SelectEntityByName("Statbox1", "Widgets"); + //Switch to Style tab + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Background color", "#f3e8ff"); + propPane.EnterJSContext("Border color", "#be185d"); + // Click on Deploy and ensure it is deployed appropriately + deployMode.DeployApp(); + // Ensure the Background Color is applied + agHelper.AssertCSS( + locators._statboxWidget, + "background-color", + "rgb(243, 232, 255)", + ); + //Ensure that the border colour is applied + agHelper.AssertCSS( + locators._statboxWidget, + "border-color", + "rgb(205, 213, 223)", + ); + deployMode.NavigateBacktoEditor(); + }); + + it("6. Rename, copy-paste and delete the widget", () => { + entityExplorer.RenameEntityFromExplorer("Statbox1", "Stats", true); + propPane.CopyPasteWidgetFromPropertyPane("Stats"); + entityExplorer.DeleteWidgetFromEntityExplorer("Stats"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Tab/Tabs_2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Tab/Tabs_2_spec.ts new file mode 100644 index 0000000000..b6cc1f61b4 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Tab/Tabs_2_spec.ts @@ -0,0 +1,274 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, + table, + tabs, + assertHelper, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Tabs widget Tests", function () { + before(() => { + agHelper.AddDsl("tabsDsl"); + }); + + it("1. Verify property visibility", function () { + const dataProperties = ["tabs", "defaulttab"]; + const generalProperties = [ + "visible", + "animateloading", + "showtabs", + "height", + ]; + const eventsProperties = ["ontabselected"]; + const colorsBorderShadows = [ + "accentcolor", + "backgroundcolor", + "bordercolor", + "borderwidth", + "borderradius", + "boxshadow", + ]; + + entityExplorer.SelectEntityByName("Tabs1", "Widgets"); + // Data section + dataProperties.forEach((dataSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("data", `${dataSectionProperty}`), + ); + }); + + // General section + generalProperties.forEach((generalSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "general", + `${generalSectionProperty}`, + ), + ); + }); + + // Events section + eventsProperties.forEach((eventsSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + "events", + `${eventsSectionProperty}`, + ), + ); + }); + + propPane.MoveToTab("Style"); + // Style section + colorsBorderShadows.forEach((styleSectionProperty) => { + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl( + `colors\\,bordersandshadows`, + `${styleSectionProperty}`, + ), + ); + }); + }); + + it("2. Verify Renaming, duplication and deletion", () => { + // Rename and verify + entityExplorer.RenameEntityFromExplorer("Tabs1", "NewTabs", true); + agHelper.AssertElementVisibility(locators._widgetName("NewTabs")); + + // Copy and paste widget using cmd+c and cmd+v + entityExplorer.SelectEntityByName("NewTabs", "Widgets"); + agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{c}`); + agHelper.Sleep(500); + agHelper.GetElement("body").type(`{${agHelper._modifierKey}}{v}`); + agHelper.Sleep(1000); + entityExplorer.ExpandCollapseEntity("Tab 1"); + entityExplorer.AssertEntityPresenceInExplorer("NewTabsCopy"); + entityExplorer.DeleteWidgetFromEntityExplorer("NewTabsCopy"); + + // Copy paste from property pane and delete from property pane + propPane.CopyPasteWidgetFromPropertyPane("NewTabs"); + propPane.DeleteWidgetFromPropertyPane("NewTabsCopy"); + entityExplorer.SelectEntityByName("NewTabs", "Widgets"); + propPane.MoveToTab("Content"); + }); + + it("3. Verify Binding with text widget", () => { + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.UpdatePropertyFieldValue("Text", "{{NewTabs.selectedTab}}"); + agHelper.GetNClick(propPane._tabId1); + agHelper.AssertText(locators._textInside, "text", "Tab 1"); + agHelper.GetNClick(propPane._tabId2); + agHelper.AssertText(locators._textInside, "text", "Tab 2"); + + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.UpdatePropertyFieldValue("Text", "{{NewTabs.isVisible}}"); + entityExplorer.SelectEntityByName("NewTabs", "Widgets"); + propPane.TogglePropertyState("visible", "Off"); + agHelper.AssertText(locators._textInside, "text", "false"); + propPane.TogglePropertyState("visible", "On"); + agHelper.AssertText(locators._textInside, "text", "true"); + }); + + it("4. Validate when 'Show Tabs' is set to False, all the Tabs get hidden", () => { + propPane.TogglePropertyState("showtabs", "Off"); + agHelper.AssertElementAbsence(propPane._tabId1); + agHelper.AssertElementAbsence(propPane._tabId2); + propPane.TogglePropertyState("showtabs", "On"); + agHelper.AssertElementVisibility(propPane._tabId1); + agHelper.AssertElementVisibility(propPane._tabId2); + }); + + it("5. Verify settings, delete and add button associated with tabs", () => { + agHelper.AssertElementLength(propPane._tableEditColumnButton, 2); + agHelper.AssertElementLength(table._deleteColumn, 2); + + propPane.OpenTableColumnSettings("tab1"); + agHelper.AssertElementVisibility( + propPane._propertyPanePropertyControl("general", "visible"), + ); + propPane.TogglePropertyState("visible", "Off"); + agHelper.AssertElementAbsence(propPane._tabId1); + agHelper.AssertClassExists(`${propPane._tabId2} span`, "is-selected"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementAbsence(propPane._tabId1); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementAbsence(propPane._tabId1); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewTabs", "Widgets"); + + propPane.OpenTableColumnSettings("tab1"); + propPane.TogglePropertyState("visible", "On"); + agHelper.AssertElementVisibility(propPane._tabId1); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertElementVisibility(propPane._tabId1); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertElementVisibility(propPane._tabId1); + deployMode.NavigateBacktoEditor(); + + entityExplorer.SelectEntityByName("NewTabs", "Widgets"); + + // Delete tab + agHelper.GetNClick(table._deleteColumn, 1); + agHelper.AssertElementAbsence(propPane._tabId2); + + // Add tab + agHelper.GetNClick(tabs._addTab); + agHelper.AssertText(tabs._placeholderTabTitle, "val", "Tab 2", 1); + }); + + it("6. Validate auto height with limits", function () { + propPane.SelectPropertiesDropDown("height", "Auto Height with limits"); + agHelper.HoverElement(propPane._autoHeightLimitMin); + agHelper.AssertContains("Min-Height: 15 rows"); + agHelper.HoverElement(propPane._autoHeightLimitMax); + agHelper.AssertContains("Max-Height: 21 rows"); + propPane.SelectPropertiesDropDown("height", "Auto Height"); + }); + + // to work on redesign of the test, commenting for now + it.skip("7. Verify colors, borders and shadows", () => { + // Verify font color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("accentcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("accentcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + + // Background color + agHelper.GetNClick(propPane._propertyControlColorPicker("backgroundcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + propPane.ToggleJSMode("backgroundcolor", true); + propPane.UpdatePropertyFieldValue("Background color", "#eab308"); + agHelper.AssertCSS( + tabs._tabsWidgetStyle, + "background-color", + "rgb(234, 179, 8)", + ); + propPane.ToggleJSMode("backgroundcolor", false); + + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 1); + propPane.TogglePropertyState("backgroundcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 1); + + // Border Color + propPane.SelectColorFromColorPicker("bordercolor", 13); + assertHelper.AssertNetworkStatus("@updateLayout"); + agHelper.AssertCSS( + tabs._tabsWidgetStyle, + "border-color", + "rgb(185, 28, 28)", + ); + + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 2); + propPane.TogglePropertyState("bordercolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 2); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS(tabs._tabsWidgetStyle, "border-radius", "0px"); + + // Verify Box Shadow + agHelper.GetNClick(`${propPane._segmentedControl("0")}:contains('Large')`); + assertHelper.AssertNetworkStatus("@updateLayout"); + agHelper.AssertCSS( + tabs._tabsWidgetStyle, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px", + ); + }); + + it("8. Checks validation error in default selected tab", () => { + entityExplorer.SelectEntityByName("NewTabs", "Widgets"); + + propPane.MoveToTab("Content"); + + propPane.TypeTextIntoField("Default tab", "Tab 11", true); + + agHelper.VerifyEvaluatedErrorMessage("Tab name Tab 11 does not exist"); + + agHelper.ClearNType( + locators._draggableFieldConfig("tab1") + " input", + "Tab 11", + 0, + ); + + agHelper.AssertAutoSave(); + + agHelper.Sleep(1000); + + agHelper.FocusElement(locators._propertyInputField("Default tab")); + + agHelper.AssertElementAbsence(locators._evaluatedErrorMessage); + + propPane.TypeTextIntoField("Default tab", "Tab 13", true); + + agHelper.VerifyEvaluatedErrorMessage("Tab name Tab 13 does not exist"); + + agHelper.AssertAutoSave(); + + agHelper.Sleep(1000); + + cy.reload(); + + entityExplorer.SelectEntityByName("NewTabs", "Widgets"); + + agHelper.FocusElement(locators._propertyInputField("Default tab")); + + agHelper.VerifyEvaluatedErrorMessage("Tab name Tab 13 does not exist"); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/TableFilter2_1_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/TableFilter2_1_Spec.ts index f99213d507..9e5875e552 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/TableFilter2_1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/TableFilter2_1_Spec.ts @@ -218,8 +218,7 @@ describe("Verify various Table_Filter combinations", function () { _.table.RemoveFilterNVerify("2381224", true, false); }); - //Skipping until bug closed - it.skip("8. Verify Table Filter for changing from AND -> OR [Remove a filter] -> AND + Bug 12642", function () { + it("8. Verify Table Filter for changing from AND -> OR [Remove a filter] -> AND + Bug 12642", function () { _.table.OpenNFilterTable("id", "contains", "7"); _.table.ReadTableRowColumnData(1, 4).then(($cellData) => { expect($cellData).to.eq("Beef steak"); @@ -241,11 +240,7 @@ describe("Verify various Table_Filter combinations", function () { expect($cellData).to.eq("Tuna Salad"); }); - _.table.RemoveFilterNVerify("2381224", false, true, 0); //Verifies bug 12642 - - _.agHelper.GetNClick(_.table._filterOperatorDropdown); - cy.get(_.table._dropdownText).contains("AND").click(); - _.agHelper.ClickButton("APPLY"); + _.table.RemoveFilterNVerify("7434532", false, true, 0); //Since TableV1 - revertion of operator upon removal of filter is not supported _.table.ReadTableRowColumnData(0, 4).then(($cellData) => { expect($cellData).to.eq("Avocado Panini"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Button_Icon_validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Button_Icon_validation_spec.js index a3ec468452..b337d0ac81 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Button_Icon_validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Button_Icon_validation_spec.js @@ -34,7 +34,10 @@ describe("Table Widget property pane feature validation", function () { // Changing the computed value (data) to "orderAmount" cy.updateComputedValue(testdata.currentRowOrderAmt); cy.changeColumnType("Button", false); - cy.get(widgetsPage.buttonColor).click({ force: true }).clear().type(color); + cy.get(widgetsPage.buttonColor) + .click({ force: true }) + .clear() + .type(color, { delay: 0 }); cy.get(widgetsPage.tableBtn).should("have.css", "background-color", color); cy.readTabledataPublish("2", "2").then((tabData) => { const tabValue = tabData; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Color_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Color_spec.js index 144933d02c..368d8c5e23 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Color_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Color_spec.js @@ -21,7 +21,7 @@ describe("Table Widget property pane feature validation", function () { cy.get(widgetsPage.textColor) .scrollIntoView() .clear({ force: true }) - .type("purple", { force: true }); + .type("purple", { force: true, delay: 0 }); cy.wait("@updateLayout"); // Verify the text color is purple cy.readTabledataValidateCSS("1", "0", "color", "rgb(128, 0, 128)"); @@ -51,7 +51,7 @@ describe("Table Widget property pane feature validation", function () { `${widgetsPage.cellBackground_tablev1} [data-testid='t--color-picker-input']`, ) .clear({ force: true }) - .type("purple", { force: true }); + .type("purple", { force: true, delay: 0 }); cy.wait("@updateLayout"); cy.assertPageSave(); _.deployMode.DeployApp(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_MultiRowSelect_dataUpdation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_MultiRowSelect_dataUpdation_spec.js index 8586d01ed3..0856b562d0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_MultiRowSelect_dataUpdation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_MultiRowSelect_dataUpdation_spec.js @@ -1,5 +1,11 @@ const widgetsPage = require("../../../../../locators/Widgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + entityExplorer, + propPane, + table, +} from "../../../../../support/Objects/ObjectsCore"; /* Selected row stays selected after data updation @@ -7,14 +13,20 @@ if the primary column value isn't updated. */ describe("Table Widget row multi select validation", function () { before(() => { - _.agHelper.AddDsl("multiSelectedRowUpdationDsl"); + agHelper.AddDsl("multiSelectedRowUpdationDsl"); }); - it("Test multi select column shows when enableMultirowselection is true", function () { - cy.get(widgetsPage.buttonWidget).first().click(); - cy.wait(1000); - cy.get(".t--table-multiselect").first().click(); + it("Test multi select column shows when enableMultirowselection is true and not when enableMultirowselection is off", function () { + agHelper.GetNClick(widgetsPage.buttonWidget); cy.get(widgetsPage.buttonWidget).last().click(); - cy.get(".tbody .tr").first().should("have.class", "selected-row"); + deployMode.DeployApp(); + agHelper.GetNClick(table._multirowselect, 1); + agHelper.GetNClick(table._multirowselect, 2); + agHelper.AssertElementLength(table._selectedrow, 2); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Table1"); + propPane.TogglePropertyState("Enable multi row selection", "Off"); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(table._multirowselect); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_PropertyPane_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_PropertyPane_2_spec.js index b83f6c5f6a..21fbad3fc3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_PropertyPane_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_PropertyPane_2_spec.js @@ -52,7 +52,7 @@ describe("Table Widget property pane feature validation", function () { deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); table.WaitUntilTableLoad(0, 0, "v1"); // Change the Search text - cy.get(widgetsPage.searchField).type("Hello"); + cy.get(widgetsPage.searchField).first().type("Hello"); // Verify the search text is changed cy.get(commonlocators.toastmsg).contains("Search Text Changed"); deployMode.NavigateBacktoEditor(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Widget_Add_button_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Widget_Add_button_spec.js index 0c76fe7509..ad839b7d96 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Widget_Add_button_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV1/Table_Widget_Add_button_spec.js @@ -82,7 +82,7 @@ describe("Table Widget property pane feature validation", function () { cy.get(widgetsPage.buttonColor) .click({ force: true }) .clear() - .type(color1, { force: true }); + .type(color1, { force: true, delay: 0 }); cy.get(widgetsPage.tableBtn).should("have.css", "background-color", color1); // Changing the color again to reproduce issue #9526 @@ -92,7 +92,7 @@ describe("Table Widget property pane feature validation", function () { .clear() // following wait is required to reproduce #9526 .wait(600) - .type(color2); + .type(color2, { delay: 0 }); cy.get(widgetsPage.tableBtn).should("have.css", "background-color", color2); }); @@ -174,7 +174,7 @@ describe("Table Widget property pane feature validation", function () { .click() .clear() .click({ force: true }) - .type(color1); + .type(color1, { delay: 0 }); cy.get(widgetsPage.tableBtn).should("have.css", "background-color", color1); @@ -185,7 +185,7 @@ describe("Table Widget property pane feature validation", function () { .click({ force: true }) // following wait is required to reproduce #9526 .wait(500) - .type(color2); + .type(color2, { delay: 0 }); cy.get(widgetsPage.tableBtn).should("have.css", "background-color", color2); // Add a Menu item 1 diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js index d4f0bb1ed7..c095eeaa49 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js @@ -11,42 +11,32 @@ describe("Basic flow ", () => { cy.openPropertyPane("tablewidgetv2"); cy.get(".t--property-control-allowaddingarow").should("exist"); cy.get(".t--property-control-allowaddingarow input").should("exist"); - }); - - it("1.2. should test that Add new row link appears on the UI when the allow add new row property is enabled", () => { cy.get(".t--add-new-row").should("not.exist"); - _.propPane.TogglePropertyState("Allow adding a row", "On"); - cy.get(".t--add-new-row").should("exist"); _.propPane.TogglePropertyState("Allow adding a row", "Off"); cy.get(".t--add-new-row").should("not.exist"); - }); - - it("1.3. should test that onSave, onDiscard and default row are showing up only when the allow add new property is enabled", () => { cy.get(".t--property-control-onsave").should("not.exist"); cy.get(".t--property-control-ondiscard").should("not.exist"); cy.get(".t--property-control-defaultvalues").should("not.exist"); + // onSave, onDiscard and default row are showing up only when the allow add new property is enabled _.propPane.TogglePropertyState("Allow adding a row", "On"); + cy.get(".t--add-new-row").should("exist"); cy.get(".t--property-control-onsave").should("exist"); cy.get(".t--property-control-ondiscard").should("exist"); cy.get(".t--property-control-defaultvalues").should("exist"); - }); - - it("1.4. should test that add new row link is disabled during the inline editing flow", () => { cy.get(".t--add-new-row.disabled").should("not.exist"); + // add new row link is disabled during the inline editing flow cy.makeColumnEditable("step"); cy.editTableCell(0, 0); cy.get(".t--add-new-row.disabled").should("exist"); - }); - - it("1.5. should test that clicking on add new row link adds an empty row at the top of the table", () => { cy.openPropertyPane("tablewidgetv2"); cy.get(".tableWrap .new-row").should("not.exist"); + // clicking on add new row link adds an empty row at the top of the table cy.get(".t--add-new-row").click(); cy.get(".tableWrap .new-row").should("exist"); cy.get(".t--discard-new-row").click({ force: true }); }); - it("1.6. should test that new row is getting populated with the default row property value", () => { + it("1.2. should test that new row is getting populated with the default row property value", () => { cy.updateCodeInput( ".t--property-control-defaultvalues", "{{{step: 'newStepCell'}}}", @@ -59,7 +49,7 @@ describe("Basic flow ", () => { cy.get(".t--discard-new-row").click({ force: true }); }); - it("1.7. should test that inline editing, row selection, pagination, search, filters are actions cannot be performed while in add new row feature", () => { + it("1.3. should test that inline editing, row selection, pagination, search, filters are actions cannot be performed while in add new row feature", () => { cy.get(".t--widget-tablewidgetv2 .t--search-input").should("exist"); cy.get(".t--widget-tablewidgetv2 .t--table-filter-toggle-btn").should( "exist", @@ -100,7 +90,7 @@ describe("Basic flow ", () => { cy.get(".t--discard-new-row").click({ force: true }); }); - it("1.8. should test that only editable column cells are in editmode in the new row", () => { + it("1.4. should test that only editable column cells are in editmode in the new row", () => { cy.get(".t--add-new-row").click(); cy.get(`[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor`).should( "exist", @@ -125,7 +115,7 @@ describe("Basic flow ", () => { ); }); - it("1.9. should test that newRow property holds the entered data", () => { + it("1.5. should test that newRow property holds the entered data", () => { cy.makeColumnEditable("step"); cy.makeColumnEditable("task"); cy.enterTableCellValue(0, 0, "22"); @@ -139,7 +129,7 @@ describe("Basic flow ", () => { ); }); - it("1.10. should test that non data (iconBitton, button, menubutton) column cells are not showing up", () => { + it("1.6. should test that non data (iconBitton, button, menubutton) column cells are not showing up", () => { cy.openPropertyPane("tablewidgetv2"); cy.editColumn("step"); ["Button", "Menu button", "Icon button"].forEach((columnType) => { @@ -150,7 +140,8 @@ describe("Basic flow ", () => { }); cy.get("[data-testid='t--property-pane-back-btn']").click(); }); - it("1.11. should not hide the header section when add new row button is enabled and another header element is disabled", () => { + + it("1.7. should not hide the header section when add new row button is enabled and another header element is disabled", () => { cy.get(".t--discard-new-row").click({ force: true }); //disable all header widgets for the table [ diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js index 6c69fa09b6..e16c2b3d5c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js @@ -144,9 +144,7 @@ describe("Validation flow", () => { cy.get(".error-tooltip .bp3-popover-content").should("not.exist"); cy.get(`[data-colindex=0][data-rowindex=0] input`).focus(); cy.get(".error-tooltip .bp3-popover-content").should("have.length", 1); - }); - - it("2.5. should test that save button is disabled when there is an error", () => { + // save button is disabled when there is an error cy.get(".t--save-new-row").should("be.disabled"); cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 2); cy.enterTableCellValue(0, 0, "1"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_1_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_1_spec.ts index 7d7a16da40..ffa81cba36 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_1_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_1_spec.ts @@ -40,6 +40,7 @@ describe("Table widget date column inline editing functionality", () => { ); agHelper.AssertElementAbsence(table._dateInputPopover); agHelper.AssertElementAbsence(table._editCellEditor); + agHelper.WaitUntilToastDisappear("onDateSelected"); agHelper .GetText(`${table._tableRow1Child3}`) .then(($textData) => expect($textData).to.eq(`2021-05-17T00:00:00`)); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_2_spec.ts index e31eb8a5aa..5f8ad27c17 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_2_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Date_column_editing_2_spec.ts @@ -4,60 +4,17 @@ import { agHelper, locators, propPane, - assertHelper, + dataSources, } from "../../../../../support/Objects/ObjectsCore"; +import { datePickerlocators } from "../../../../../locators/WidgetLocators"; + describe("Table widget date column inline editing functionality", () => { before(() => { agHelper.AddDsl("Table/DateCellEditingDSL"); }); - it.skip("1. should check that changing property pane time precision changes the date picker time precision", () => { - entityExplorer.SelectEntityByName("Table1"); - table.EditColumn("release_date", "v2"); - agHelper.GetNClick(table._timeprecisionPopover, 0); - agHelper - .GetElement(locators._dropdownText) - .children() - .contains("Minute") - .click(); - agHelper.GetElement(table._tableRow1Child3).dblclick({ - force: true, - }); - agHelper.AssertElementExist(table._timePickerHour); - agHelper.AssertElementExist(table._timePickerMinute); - agHelper.AssertElementAbsence(table._timePickerSecond); - - entityExplorer.SelectEntityByName("Table1"); - table.EditColumn("release_date", "v2"); - agHelper.GetNClick(table._timeprecisionPopover, 0); - agHelper - .GetElement(locators._dropdownText) - .children() - .contains("None") - .click(); - agHelper.GetElement(table._tableRow1Child3).dblclick({ - force: true, - }); - agHelper.AssertElementAbsence(table._timePickerRow); - - entityExplorer.SelectEntityByName("Table1"); - table.EditColumn("release_date", "v2"); - agHelper.GetNClick(table._timeprecisionPopover, 1); - agHelper - .GetElement(locators._dropdownText) - .children() - .contains("Second") - .click(); - agHelper.GetElement(table._tableRow1Child3).dblclick({ - force: true, - }); - agHelper.AssertElementExist(table._timePickerHour); - agHelper.AssertElementExist(table._timePickerMinute); - agHelper.AssertElementExist(table._timePickerSecond); - }); - - it("2. should check visible property control functionality", () => { + it("1. should check visible property control functionality", () => { entityExplorer.SelectEntityByName("Table1"); table.EditColumn("release_date", "v2"); propPane.TogglePropertyState("Visible", "Off"); @@ -71,52 +28,42 @@ describe("Table widget date column inline editing functionality", () => { table.AssertVisibleColumns(["release_date"]); }); - // ADS changes to date input property causes this test to fail - // skipping it temporarily. - it.skip("3. should check min date and max date property control functionality", () => { + it("2. should check min date and max date property control functionality", () => { entityExplorer.SelectEntityByName("Table1"); - table.EditColumn("release_date", "v2"); + propPane.TogglePropertyState("Editable", "On"); agHelper.AssertElementExist( propPane._propertyPanePropertyControl("validation", "mindate"), ); agHelper.AssertElementExist( propPane._propertyPanePropertyControl("validation", "maxdate"), ); - agHelper.RemoveCharsNType( - `${propPane._propertyPanePropertyControl("validation", "mindate")} ${ - table._lastChildDatePicker - }`, - -1, - "2022-05-05T00:00:10.1010+05:30{enter}", - ); - agHelper.RemoveCharsNType( - `${propPane._propertyPanePropertyControl("validation", "mindate")} ${ - table._lastChildDatePicker - }`, - -1, - "2022-05-30T00:00:10.1010+05:30{enter}", - ); + agHelper.GetNClick(locators._existingFieldTextByName("Min Date")); + agHelper.GetNClick(datePickerlocators.calendarHeader, 2); + agHelper.GetNClick(datePickerlocators.year("2022"), 0, true); + agHelper.GetNClick(datePickerlocators.calendarHeader, 1); + agHelper.GetNClick(dataSources._visibleTextSpan("May"), 0, true); + agHelper.GetNClick(datePickerlocators.date("005")); + agHelper.PressEnter(); + agHelper.GetNClick(locators._existingFieldTextByName("Min Date")); + agHelper.GetNClick(datePickerlocators.calendarHeader, 2); + agHelper.GetNClick(datePickerlocators.year("2022"), 0, true); + agHelper.GetNClick(datePickerlocators.date("030")); table.ClickOnEditIcon(0, 2); agHelper .GetText(table._popoverErrorMsg("Date out of range")) .then(($textData) => expect($textData).to.eq("Date out of range")); - agHelper.RemoveCharsNType( - `${propPane._propertyPanePropertyControl("validation", "mindate")} ${ - table._lastChildDatePicker - }`, - -1, - "{enter}", - ); - agHelper.RemoveCharsNType( - `${propPane._propertyPanePropertyControl("validation", "maxdate")} ${ - table._lastChildDatePicker - }`, - -1, - "{enter}", - ); + + agHelper.GetNClick(locators._existingFieldTextByName("Min Date")); + agHelper.ClickButton("Clear"); + + agHelper.GetNClick(locators._existingFieldTextByName("Max Date")); + agHelper.ClickButton("Clear"); + + table.ClickOnEditIcon(0, 2); + agHelper.AssertElementAbsence(table._popoverErrorMsg("Date out of range")); }); - it("4. should allow ISO 8601 format date and not throw a disallowed validation error", () => { + it("3. should allow ISO 8601 format date and not throw a disallowed validation error", () => { entityExplorer.SelectEntityByName("Table1"); propPane.NavigateBackToPropertyPane(); propPane.UpdatePropertyFieldValue( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js index 13cf1be4dc..40df5e635c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js @@ -4,6 +4,7 @@ import { agHelper, entityExplorer, propPane, + table, } from "../../../../../support/Objects/ObjectsCore"; describe("Table widget v2 edge case scenario testing", function () { @@ -32,15 +33,6 @@ describe("Table widget v2 edge case scenario testing", function () { "have.text", "[ 1]", ); - - propPane.TogglePropertyState("Enable multi-row selection", "Off"); //Disable Multi row select - - propPane.TogglePropertyState("Enable multi-row selection", "On"); //Enable Multi row select - - cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should( - "have.text", - "[ 1]", - ); }); it("2. Check if the selectedRowIndices does not contain -1", function () { @@ -62,11 +54,12 @@ describe("Table widget v2 edge case scenario testing", function () { //Check the value present in the textfield which is selectedRowIndices is [] cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should("have.text", "[]"); + cy.wait(1000); //Select the 1st, 2nd and 3rd row - cy.isSelectRow("0"); - cy.isSelectRow("1"); - cy.isSelectRow("2"); + table.SelectTableRow(0, 0, true, "v2"); + table.SelectTableRow(1, 0, true, "v2"); + table.SelectTableRow(2, 0, true, "v2"); //Check the value present in the textfield which is selectedRowIndices is [0,1,2] cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js index 6a21aac6a3..2386ddefce 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js @@ -146,7 +146,7 @@ describe("Table widget inline editing functionality", () => { cy.editTableCell(0, 2); cy.enterTableCellValue(0, 2, "#14").type("{enter}"); cy.openPropertyPane("tablewidgetv2"); - cy.get(widgetsPage.tabedataField).type("{backspace}"); + cy.get(widgetsPage.tabedataField).type("{cmd}{a} {backspace}"); cy.wait(300); cy.get(commonlocators.textWidgetContainer).should("contain.text", -1); }); @@ -188,7 +188,7 @@ describe("Table widget inline editing functionality", () => { table.EditTableCell(2, 0, "#14"); cy.get(commonlocators.textWidgetContainer).should("contain.text", 2); cy.openPropertyPane("tablewidgetv2"); - cy.get(widgetsPage.tabedataField).type("{backspace}"); + cy.get(widgetsPage.tabedataField).type("{cmd}{a} {backspace}"); cy.wait(300); cy.get(commonlocators.textWidgetContainer).should("contain.text", -1); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts index a67ce9fa2a..55efc3fe8a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts @@ -18,7 +18,7 @@ describe("Verify various Table_Filter combinations", function () { JSON.stringify(this.dataSet.TableInput), ); assertHelper.AssertNetworkStatus("@updateLayout", 200); - cy.get("body").type("{esc}"); + agHelper.PressEscape(); table.ChangeColumnType("id", "Plain text", "v2"); table.ChangeColumnType("orderAmount", "Plain text", "v2"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts index fd8dac7e63..40180294d9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts @@ -229,8 +229,7 @@ describe("Verify various Table_Filter combinations", function () { table.RemoveFilterNVerify("2381224", true, false, 0, "v2"); }); - //Skipping until bug closed - it.skip("8. Verify Table Filter for changing from AND -> OR [Remove a filter] -> AND + Bug 12642", function () { + it("8. Verify Table Filter for changing from AND -> OR [Remove a filter] -> AND + Bug 12642", function () { table.OpenNFilterTable("id", "contains", "7"); table.ReadTableRowColumnData(1, 4, "v2").then(($cellData) => { expect($cellData).to.eq("Beef steak"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js index 69d022d44e..8dd32f5614 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Button_Icon_validation_spec.js @@ -36,7 +36,10 @@ describe("Table Widget V2 property pane feature validation", function () { cy.updateComputedValue(testdata.currentRowOrderAmt); cy.changeColumnType("Button"); cy.moveToStyleTab(); - cy.get(widgetsPage.buttonColor).click({ force: true }).clear().type(color); + cy.get(widgetsPage.buttonColor) + .click({ force: true }) + .clear() + .type(color, { delay: 0 }); cy.get(widgetsPage.tableV2Btn).should( "have.css", "background-color", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Color_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Color_spec.js index d6acfdc66d..f9dd3c2918 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Color_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Color_spec.js @@ -29,7 +29,7 @@ describe("Table Widget V2 property pane feature validation", function () { cy.get(widgetsPage.textColor) .scrollIntoView() .clear({ force: true }) - .type("purple", { force: true }); + .type("purple", { force: true, delay: 0 }); cy.wait("@updateLayout"); // Verify the text color is purple cy.readTableV2dataValidateCSS("1", "0", "color", "rgb(128, 0, 128)"); @@ -59,7 +59,7 @@ describe("Table Widget V2 property pane feature validation", function () { `.t--property-control-cellbackgroundcolor [data-testid='t--color-picker-input']`, ) .clear({ force: true }) - .type("purple", { force: true }); + .type("purple", { force: true, delay: 0 }); cy.wait("@updateLayout"); //cy.assertPageSave(); _.deployMode.DeployApp(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts index 59195265ce..eb1ec4f80e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts @@ -65,7 +65,7 @@ describe("Table V2 sort & filter using display text functionality", () => { true, false, ); - agHelper.RemoveEvaluatedPopUp(); + agHelper.RemoveUIElement("EvaluatedPopUp"); table.OpenNFilterTable("name", "contains", "Y"); table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { expect($cellData).to.eq("Y"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_1_spec.js index 9c5c1bd06c..fa0987bc7d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_1_spec.js @@ -82,7 +82,7 @@ describe("Table Widget V2 property pane feature validation", function () { deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); table.WaitUntilTableLoad(0, 0, "v2"); // Change the Search text - cy.get(widgetsPage.searchField).type("Hello"); + cy.get(widgetsPage.searchField).first().type("Hello"); // Verify the search text is changed agHelper.ValidateToastMessage("Search Text Changed"); deployMode.NavigateBacktoEditor(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Url_Column_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Url_Column_spec.ts index 501520e944..43383ce8d1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Url_Column_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Url_Column_spec.ts @@ -1,28 +1,29 @@ -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + table, +} from "../../../../../support/Objects/ObjectsCore"; describe("16108 - Verify Table URL column bugs", function () { before(() => { - _.agHelper.AddDsl("tableV2WithUrlColumnDsl"); + agHelper.AddDsl("tableV2WithUrlColumnDsl"); }); it("Verify click on URL column with display text takes to the correct link", function () { - _.deployMode.DeployApp(); - - _.table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { + deployMode.DeployApp(); + table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { expect($cellData).to.eq("Profile pic"); }); - - _.table.ReadTableRowColumnData(3, 0, "v2").then(($cellData) => { + table.ReadTableRowColumnData(3, 0, "v2").then(($cellData) => { expect($cellData).to.eq("Profile pic"); }); - - _.table.AssertURLColumnNavigation( + table.AssertURLColumnNavigation( 0, 0, "https://randomuser.me/api/portraits/med/women/39.jpg", "v2", ); - _.table.AssertURLColumnNavigation( + table.AssertURLColumnNavigation( 3, 0, "https://randomuser.me/api/portraits/med/men/52.jpg", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Add_button_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Add_button_spec.js index c06eeb4d9f..4ff8d09bb0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Add_button_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Add_button_spec.js @@ -55,7 +55,7 @@ describe("Table Widget V2 property pane feature validation", function () { cy.editColumn("id"); const color1 = "rgb(255, 0, 0)"; cy.moveToStyleTab(); - cy.get(widgetsPage.buttonColor).click({ force: true }).clear().type(color1); + propPane.EnterJSContext("Button color", color1); cy.get(widgetsPage.tableV2Btn).should( "have.css", "background-color", @@ -64,31 +64,23 @@ describe("Table Widget V2 property pane feature validation", function () { // Changing the color again to reproduce issue #9526 const color2 = "rgb(255, 255, 0)"; - cy.get(widgetsPage.buttonColor) - .click({ force: true }) - .clear() - // following wait is required to reproduce #9526 - .wait(600) - .type(color2); + propPane.EnterJSContext("Button color", color2); + cy.get(widgetsPage.tableV2Btn).should( "have.css", "background-color", color2, - ); - }); - - it("3. Table widget triggeredRow property should be accessible", function () { + ); //verifying Bug #9526 - color is not reverted back to default + //Table widget triggeredRow property should be accessible", function () { cy.get(commonlocators.TextInside).should("have.text", "Tobias Funke"); - }); - - it("4. Table widget triggeredRow property should be same even after sorting the table", function () { + // Table widget triggeredRow property should be same even after sorting the table", function () { //sort table date on second column cy.get(".draggable-header ").first().click({ force: true }); cy.wait(1000); cy.get(commonlocators.TextInside).should("have.text", "Tobias Funke"); }); - it("5. Table widget add new icon button column", function () { + it("3. Table widget add new icon button column", function () { cy.get("[data-testid='t--property-pane-back-btn']").click({ force: true }); // hide id column cy.makeColumnVisible("id"); @@ -123,7 +115,7 @@ describe("Table Widget V2 property pane feature validation", function () { cy.deleteColumn("customColumn1"); }); - it("6. Table widget add new menu button column", function () { + it("4. Table widget add new menu button column", function () { cy.openPropertyPane("tablewidgetv2"); // click on Add new Column. cy.get(".t--add-column-btn").click(); @@ -279,14 +271,13 @@ describe("Table Widget V2 property pane feature validation", function () { }); }); - it("7. Table widget test on button icon click, row should not get deselected", () => { + it("5. Table widget test on button icon click, row should not get deselected", () => { cy.get(widgetsPage.tableV2IconBtn).last().click({ force: true }); cy.get(commonlocators.TextInside).should("have.text", "Tobias Funke"); //click icon button again cy.get(widgetsPage.tableV2IconBtn).last().click({ force: true }); cy.get(commonlocators.TextInside).should("have.text", "Tobias Funke"); - cy.get("[data-testid='t--property-pane-back-btn']").click({ force: true }); - cy.wait(500); - cy.get("[data-testid='t--property-pane-back-btn']").click({ force: true }); + propPane.NavigateBackToPropertyPane(false); + propPane.NavigateBackToPropertyPane(); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Copy_Paste_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Copy_Paste_spec.js index a99414302e..64ca8476a1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Copy_Paste_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Copy_Paste_spec.js @@ -1,6 +1,7 @@ const apiwidget = require("../../../../../locators/apiWidgetslocator.json"); const commonlocators = require("../../../../../locators/commonlocators.json"); const widgetsPage = require("../../../../../locators/Widgets.json"); +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; import { agHelper, entityExplorer, @@ -47,4 +48,18 @@ describe("Test Suite to validate copy/paste table Widget V2", function () { expect($lis.eq(1)).to.contain("{{Table1Copy.selectedRows}}"); }); }); + + it("2. Should check that table binding list gets updated when .filters gets added to it", () => { + featureFlagIntercept({ release_table_serverside_filtering_enabled: true }); + cy.CheckAndUnfoldWidgets(); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Table1Copy", + action: "Show bindings", + }); + cy.wait(200); + cy.get(apiwidget.propertyList).then(function ($lis) { + expect($lis).to.have.length(23); + expect($lis.last()).to.contain("{{Table1Copy.filters}}"); + }); + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Default_Row_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Default_Row_spec.js index 130ae15c66..b118da1366 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Default_Row_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Default_Row_spec.js @@ -1,35 +1,30 @@ const widgetsPage = require("../../../../../locators/Widgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + draggableWidgets, + entityExplorer, + table, +} from "../../../../../support/Objects/ObjectsCore"; import * as _ from "../../../../../support/Objects/ObjectsCore"; describe("Table Widget V2 property pane deafult feature validation", function () { before(() => { - _.agHelper.AddDsl("defaultTableV2Dsl"); + agHelper.AddDsl("defaultTableV2Dsl"); }); it("1. Verify default table row Data", function () { - // Open property pane - cy.openPropertyPane("tablewidgetv2"); - // Open Widget side bar - cy.get(widgetsPage.addWidget).click(); - // Drag and drop table widget - cy.dragAndDropToCanvas("tablewidgetv2", { x: 200, y: 100 }); - _.table.AddSampleTableData(); - // close Widget side bar - _.entityExplorer.NavigateToSwitcher("Explorer"); - cy.wait(2000); - _.entityExplorer.SelectEntityByName("Table2"); + entityExplorer.DragNDropWidget(draggableWidgets.TABLE); + table.AddSampleTableData(); + entityExplorer.SelectEntityByName("Table2"); // Verify default array data - cy.wait(2000); cy.readTableV2dataFromSpecificIndex("0", "0", 0).then((tabData) => { const tabValue = tabData; cy.log("the table is" + tabValue); cy.get(".bp3-ui-text span").eq(1).should("have.text", tabData); }); - _.entityExplorer.SelectEntityByName("Table1"); - cy.wait(2000); + entityExplorer.SelectEntityByName("Table1"); cy.readTableV2dataFromSpecificIndex("2", "0", 1).then((tabData) => { const tabValue = tabData; cy.log("the table is" + tabValue); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Selected_row_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Selected_row_spec.js index c0aaade337..ce04ea8d06 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Selected_row_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_Widget_Selected_row_spec.js @@ -1,18 +1,17 @@ -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + entityExplorer, +} from "../../../../../support/Objects/ObjectsCore"; describe("Table Widget v2 property pane feature validation", function () { before(() => { - _.agHelper.AddDsl("tableV2AndTextDsl"); + agHelper.AddDsl("tableV2AndTextDsl"); }); it("1. Table widget v2 new menu button column should not deselect row", function () { - cy.openPropertyPane("tablewidgetv2"); - + entityExplorer.SelectEntityByName("Table1", "Widgets"); cy.get(".t--widget-textwidget").should("have.text", "0"); - cy.contains("Open Menu").click({ - force: true, - }); - cy.wait(1000); + agHelper.ClickButton("Open Menu"); cy.get(".t--widget-textwidget").should("have.text", "0"); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_misc.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_misc.js index bdde64f1cb..251e5204f2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_misc.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_misc.js @@ -1,5 +1,5 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; -import { DEFAULT_COLUMN_NAME } from "../../../../../../src/widgets/TableWidgetV2/constants"; +import { DEFAULT_COLUMN_NAME } from "../../../../../support/Constants"; describe("tests bug 20663 TypeError: Cannot read properties of undefined", function () { before(() => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Text_wrapping_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Text_wrapping_spec.js index f8a7261397..68ce1fcd82 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Text_wrapping_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Text_wrapping_spec.js @@ -1,14 +1,14 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { agHelper, propPane } from "../../../../../support/Objects/ObjectsCore"; describe("Table Widget text wrapping functionality", function () { afterEach(() => { - _.agHelper.SaveLocalStorageCache(); + agHelper.SaveLocalStorageCache(); }); beforeEach(() => { - _.agHelper.RestoreLocalStorageCache(); - _.agHelper.AddDsl("Table/TextWrappingDSL"); + agHelper.RestoreLocalStorageCache(); + agHelper.AddDsl("Table/TextWrappingDSL"); }); it("1. should check that cell is not wrapped when cell wrapping is disabled", () => { @@ -19,10 +19,8 @@ describe("Table Widget text wrapping functionality", function () { // Enable cell wrapping and check that height is more than 28px cy.openPropertyPane("tablewidgetv2"); cy.editColumn("image"); - cy.get(".t--property-control-cellwrapping input") - .first() - .click({ force: true }); - cy.wait(1000); + + propPane.TogglePropertyState("Cell wrapping", "On"); cy.getTableCellHeight(1, 0).then((height) => { expect(height).to.not.equal("28px"); }); @@ -63,10 +61,8 @@ describe("Table Widget text wrapping functionality", function () { cy.openPropertyPane("tablewidgetv2"); cy.wait(2000); cy.editColumn("email"); - cy.get(".t--property-control-cellwrapping input").click({ - force: true, - }); - cy.wait(1000); + + propPane.TogglePropertyState("Cell wrapping", "On"); cy.getTableCellHeight(2, 0).then((height) => { expect(height).to.not.equal("28px"); }); @@ -134,12 +130,12 @@ describe("Table Widget text wrapping functionality", function () { cy.getTableCellHeight(0, 0).then((height) => { expect(height).to.equal("28px"); }); - cy.get(".t--property-control-cellwrapping input").first().click(); + propPane.TogglePropertyState("Cell wrapping", "On"); cy.wait(1000); cy.getTableCellHeight(0, 0).then((height) => { expect(height).to.not.equal("28px"); }); - cy.get(".t--property-control-cellwrapping input").first().click(); + propPane.TogglePropertyState("Cell wrapping", "Off"); }); }); @@ -152,8 +148,7 @@ describe("Table Widget text wrapping functionality", function () { .then((value) => { pageSizeBeforeWrapping = value; }); - cy.get(".t--property-control-cellwrapping input").first().click(); - cy.wait(1000); + propPane.TogglePropertyState("Cell wrapping", "On"); cy.get(".t--widget-textwidget .bp3-ui-text") .invoke("text") .then((value) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/VirtualRow_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/VirtualRow_spec.js index 109e6e6fc2..3bed60afea 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/VirtualRow_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/VirtualRow_spec.js @@ -1,4 +1,8 @@ -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + propPane, + table, + agHelper, +} from "../../../../../support/Objects/ObjectsCore"; const totalRows = 100; @@ -17,17 +21,16 @@ describe("Table Widget Virtualized Row", function () { step: i, })); - _.propPane.EnterJSContext("Table data", JSON.stringify(rows)); - _.propPane.TogglePropertyState("Server side pagination", "On"); - _.propPane.TogglePropertyState("Show pagination", "Off"); + propPane.EnterJSContext("Table data", JSON.stringify(rows)); + propPane.TogglePropertyState("Server side pagination", "On"); + propPane.TogglePropertyState("Show pagination", "Off"); }); - it("1. should check that row is getting rendered", () => { + it("1. should check that virtual rows are getting rendered when scrolling through the table", () => { + // check that row is getting rendered cy.get(".tr[data-rowindex]").should("exist"); cy.get(".td[data-rowindex]").should("exist"); - }); - it("2. should check that virtual rows are getting rendered when scrolling through the table", () => { cy.get(".tr[data-rowindex]").should("not.have.length", totalRows); cy.get(".tr[data-rowindex='0']").should("exist"); cy.get(".virtual-list.simplebar-content").scrollTo("bottom"); @@ -41,10 +44,10 @@ describe("Table Widget Virtualized Row", function () { cy.get(".t--virtual-row").should("exist"); }); - it("3. should check that virtual rows feature is turned off when cell wrapping is enabled", () => { + it("2. should check that virtual rows feature is turned off when cell wrapping is enabled", () => { cy.editColumn("step"); cy.wait(500); - _.propPane.TogglePropertyState("Cell wrapping", "On"); + propPane.TogglePropertyState("Cell wrapping", "On"); cy.get(".tr[data-rowindex]").should("have.length", totalRows); cy.get(".tr[data-rowindex='0']").should("exist"); cy.get(".tr[data-rowindex='98']").should("exist"); @@ -59,13 +62,13 @@ describe("Table Widget Virtualized Row", function () { cy.get(".t--virtual-row").should("not.exist"); }); - it("4. should check that virtual rows feature is turned off when server side pagination is disabled", () => { - _.propPane.TogglePropertyState("Cell wrapping", "Off"); - _.propPane.NavigateBackToPropertyPane(); - cy.wait(500); - _.propPane.TogglePropertyState("Show pagination", "On"); - cy.wait(500); - _.propPane.TogglePropertyState("Server side pagination", "Off"); + it("3. should check that virtual rows feature is turned off when server side pagination is disabled", () => { + agHelper.AssertElementExist(table._cellWrapOn); + propPane.TogglePropertyState("Cell wrapping", "Off"); + agHelper.AssertElementExist(table._cellWrapOff); + propPane.NavigateBackToPropertyPane(); + propPane.TogglePropertyState("Show pagination", "On"); + propPane.TogglePropertyState("Server side pagination", "Off"); cy.get(".tr[data-rowindex]").should("have.length", 5); cy.get(".t--virtual-row").should("not.exist"); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/currency_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/currency_spec.ts new file mode 100644 index 0000000000..95a59e1198 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/currency_spec.ts @@ -0,0 +1,125 @@ +import * as _ from "../../../../../../support/Objects/ObjectsCore"; + +const tableData = `{{[ + { + "amount": 10000.01, + }, +]}}`; + +function updateCellValue(value) { + cy.editTableCell(0, 0); + cy.enterTableCellValue(0, 0, value); + cy.saveTableCellValue(0, 0); + _.agHelper.Sleep(500); +} + +describe("Currency column", () => { + before(() => { + _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 300, 400); + _.propPane.UpdatePropertyFieldValue( + "Text", + `{{Table1.editableCell.value}}|{{Table1.editableCell.inputValue}}|{{typeof Table1.editableCell.value}}|{{typeof Table1.editableCell.inputValue}}`, + ); + + _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TABLE); + _.propPane.EnterJSContext("Table data", tableData); + cy.makeColumnEditable("amount"); + }); + + it("1. should test that currency column is available", () => { + cy.editColumn("amount"); + cy.changeColumnType("Currency"); + cy.get(".t--property-control-currency").should("exist"); + }); + + it("2. should test that currency column properties are displayed and working", () => { + cy.get(".t--property-control-currency").should("exist"); + + cy.get(".t--property-control-decimalsallowed").should("exist"); + + cy.get(".t--property-control-notation").should("exist"); + + cy.get(".t--property-control-thousandseparator").should("exist"); + }); + + it("3. should test that currency column is formatted correctly", () => { + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("$ 10,000"); + }); + + _.propPane.ToggleJSMode("Currency", true); + + _.propPane.EnterJSContext("Currency", "INR"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 10,000"); + }); + + _.propPane.SelectPropertiesDropDown("Decimals allowed", "1"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 10,000.0"); + }); + + _.propPane.SelectPropertiesDropDown("Decimals allowed", "2"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 10,000.01"); + }); + + _.propPane.TogglePropertyState("Thousand separator", false); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 10000.01"); + }); + + _.propPane.SelectPropertiesDropDown("Notation", "Compact"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 10.00K"); + }); + + _.propPane.SelectPropertiesDropDown("Decimals allowed", "0"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 10K"); + }); + }); + + it("4. shoudl test that currency column is editable", () => { + _.propPane.SelectPropertiesDropDown("Notation", "Standard"); + + updateCellValue("1,234.23"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 123423"); + }); + + _.propPane.SelectPropertiesDropDown("Decimals allowed", "1"); + + updateCellValue("4321.23"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 4321.2"); + }); + + _.propPane.SelectPropertiesDropDown("Decimals allowed", "2"); + + updateCellValue("1234.23"); + + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("₹ 1234.23"); + }); + + cy.editTableCell(0, 0); + + cy.enterTableCellValue(0, 0, 6543.23); + + cy.get(".t--widget-textwidget .t--text-widget-container").should( + "have.text", + "6543.23|6543.23|number|string", + ); + + cy.saveTableCellValue(0, 0); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/server_side_filtering_spec_1.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/server_side_filtering_spec_1.ts new file mode 100644 index 0000000000..8c2addab72 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/server_side_filtering_spec_1.ts @@ -0,0 +1,131 @@ +import { + entityExplorer, + propPane, + agHelper, + draggableWidgets, + table, + locators, + dataSources, +} from "../../../../../support/Objects/ObjectsCore"; +import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator"; +import { expandLoadMoreOptions } from "../../OneClickBinding/spec_utility"; +import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags"; + +const ALERT_SUCCESS_MSG = "Table data filtered"; + +describe("Table widget v2: test server side filtering", function () { + /** + * Initialization flow: + * 1. DnD Table widget + * 2. Connect a datasource to this table + * 3. Create a JS object + * 4. Name this object as utils + * 5. Bind it as a WHERE condition inside an SQL query + */ + before(() => { + featureFlagIntercept({ release_table_serverside_filtering_enabled: true }); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 300, 300); + + // Create SQL data-source + agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector); + agHelper.AssertElementExist(oneClickBindingLocator.otherActionSelector()); + agHelper.GetNClick( + oneClickBindingLocator.otherActionSelector("Connect new datasource"), + ); + + dataSources.CreateDataSource("MySql"); + + cy.get("@dsName").then(($dsName) => { + dataSources.CreateQueryAfterDSSaved(); + cy.wait(500); + + entityExplorer.NavigateToSwitcher("Widgets"); + agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector); + + expandLoadMoreOptions(); + agHelper.GetNClick( + oneClickBindingLocator.datasourceSelector($dsName as unknown as string), + ); + + agHelper.Sleep(3000); //for tables to populate for CI runs + + agHelper.GetNClick(oneClickBindingLocator.tableOrSpreadsheetDropdown); + agHelper.GetNClick( + oneClickBindingLocator.tableOrSpreadsheetDropdownOption("employees"), + ); + + agHelper.GetNClick(oneClickBindingLocator.connectData); + }); + }); + + it("1. should test that server side filtering properties exists in the property pane", function () { + agHelper.AssertElementExist( + propPane._propertyControl("serversidefiltering"), + ); + propPane.TogglePropertyState("serversidefiltering"); + + // Check if onTableFilterUpdate property is visible when server side filtering is turned on. + agHelper.AssertElementExist( + propPane._propertyControl("ontablefilterupdate"), + ); + + // set execute select SQL query action on table filter update: + propPane.SelectPlatformFunction("onTableFilterUpdate", "Execute a query"); + agHelper.GetNClickByContains(".single-select", "Select_employees1"); + agHelper.GetNClick(propPane._actionAddCallback("success")); + agHelper.GetNClick(locators._dropDownValue("Show alert")); + agHelper.EnterActionValue("Message", ALERT_SUCCESS_MSG); + }); + + it("2. should test that select query gets executed on filter change and no data is filtered from client-side when serverside filtering is turned on", () => { + table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { + expect(Number($cellData)).to.greaterThan(-1); + }); + table.OpenNFilterTable("employeeNumber", "greater than", "1000"); + agHelper.WaitUntilToastDisappear(ALERT_SUCCESS_MSG); + table.CloseFilter(); + table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { + expect(Number($cellData)).to.greaterThan(-1); + }); + }); + + it("3. should test that removing the table filter executes the query", () => { + table.OpenFilter(); + table.RemoveFilter(true); + agHelper.WaitUntilToastDisappear(ALERT_SUCCESS_MSG); + + //once table filter is removed assert that first row has id value greater than 0. + table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { + expect(Number($cellData)).to.greaterThan(-1); + }); + }); + + it("4. should test that data is filtered client-side when serverside filtering is turned off", () => { + propPane.TogglePropertyState("serversidefiltering", "Off"); + + table.OpenNFilterTable("employeeNumber", "is equal to", "1002"); + table.CloseFilter(); + + // check first row + table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { + expect($cellData).to.eq("1002"); + }); + }); +}); + +describe("Table v2: Server side filtering hidden behind feature flag", () => { + before(() => { + featureFlagIntercept({ release_table_serverside_filtering_enabled: false }); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 700, 300); + }); + + it("1. should test that server side filtering option and dtable.filters autocomplete should not be visible", () => { + agHelper.AssertElementAbsence( + propPane._propertyControl("serversidefiltering"), + ); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 300, 700); + entityExplorer.SelectEntityByName("Text1"); + propPane.TypeTextIntoField("Text", "{{Table1.filters"); + agHelper.AssertElementAbsence(locators._hints); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Text/Text2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Text/Text2_Spec.ts new file mode 100644 index 0000000000..64a5176d83 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Text/Text2_Spec.ts @@ -0,0 +1,375 @@ +import { getWidgetSelector } from "../../../../../locators/WidgetLocators"; +import { + agHelper, + draggableWidgets, + deployMode, + entityExplorer, + locators, + propPane, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Text widget tests", function () { + before(() => { + entityExplorer.DragNDropWidget(draggableWidgets.TEXT); + }); + + it("1. Validate binding text widget to checkbox and using HTML in Text", () => { + agHelper.AssertContains( + "Hello ", + "be.visible", + locators._widgetInCanvas(draggableWidgets.TEXT), + ); + propPane.ValidatePropertyFieldValue( + "Text", + "Hello {{appsmith.user.name || appsmith.user.email}}", + ); + propPane.UpdatePropertyFieldValue("Text", "
    sample text"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.TEXT), + "text", + "sample text", + ); + + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.UpdatePropertyFieldValue("Text", "{{CheckboxGroup1.options}}"); + entityExplorer.DragNDropWidget(draggableWidgets.CHECKBOXGROUP, 300, 450); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.TEXT), + "text", + '[ { "label": "Blue", "value": "BLUE" }, { "label": "Green", "value": "GREEN" }, { "label": "Red", "value": "RED" }]', + ); + }); + + it("2. Verify Visible property", () => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + agHelper.AssertExistingToggleState("Visible", "true"); + propPane.EnterJSContext("Visible", "{{(55>45)?false:true}}", true, true); + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.TEXT), + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.EnterJSContext("Visible", "", false); + propPane.ToggleJSMode("Visible", false); + propPane.TogglePropertyState("Visible", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.TEXT), + ); + }); + + it("3. Verify Disabled link property is JS convertible", () => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + agHelper.AssertExistingToggleState("Disable link", "false"); + propPane.UpdatePropertyFieldValue("Text", "https://docs.appsmith.com/"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper.AssertElementVisibility( + widgetLocators.textWidgetLink("https://docs.appsmith.com/"), + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.EnterJSContext( + "Disable link", + "{{(45>55)?false:true}}", + true, + true, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper.AssertElementAbsence( + widgetLocators.textWidgetLink("https://docs.appsmith.com/"), + ); + }); + + it("4. Verify Height property", () => { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.AssertPropertiesDropDownCurrentValue("Height", "Auto Height"); + propPane.AssertPropertiesDropDownValues("Height", [ + "Auto Height", + "Auto Height with limits", + "Fixed", + ]); + propPane.SelectPropertiesDropDown("Height", "Fixed"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper.AssertCSS( + getWidgetSelector(draggableWidgets.TEXT), + "height", + "50px", + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.SelectPropertiesDropDown("Height", "Auto Height with limits"); + agHelper.AssertElementVisibility(locators._autoHeightHandles); + agHelper.AssertElementVisibility(locators._autoHeightMin); + agHelper.AssertElementVisibility(locators._autoHeightMax); + propPane.SelectPropertiesDropDown("Height", "Fixed"); + }); + + it("5. Verify text widget styles", function () { + propPane.MoveToTab("Style"); + //General + propPane.AssertPropertiesDropDownCurrentValue( + "Font family", + "System Default", + ); + propPane.SelectPropertiesDropDown("Font family", "Poppins"); + propPane.AssertPropertiesDropDownCurrentValue("Font size", "M"); + propPane.SelectPropertiesDropDown("Font size", "S"); + //color + propPane.SelectColorFromColorPicker("textcolor", 12); + propPane.SelectColorFromColorPicker("backgroundcolor", 9); + propPane.SelectColorFromColorPicker("bordercolor", 6); + //text formatting + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.GetNClick(locators._alignment("RIGHT")); + //Border and shadow + propPane.UpdatePropertyFieldValue("Border width", "24"); + + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "color", + ) + .then((textColor: any) => { + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "background", + ) + .then((backgroundColor: any) => { + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer, + "border-color", + ) + .then((borderColor: any) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.TEXT), + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "color", + textColor, + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "background", + backgroundColor, + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer, + "border-color", + borderColor, + ); + }); + }); + }); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div", + "font-family", + "Poppins", + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "font-size", + "14px", + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "font-weight", + "400", + ); + agHelper.AssertAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "textalign", + "RIGHT", + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer, + "border-width", + "24px", + ); + }); + + it("6. Verify text widget styles are JS convertible", function () { + //JS conversion + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.EnterJSContext("Font family", "Inter"); + propPane.EnterJSContext("Font size", "1.5rem"); + propPane.EnterJSContext("Text color", "#71717a"); + propPane.EnterJSContext("Background color", "#fca5a5"); + propPane.EnterJSContext("Alignment", "LEFT"); + propPane.EnterJSContext("Emphasis", "ITALIC"); + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "color", + ) + .then((textColor: any) => { + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "background", + ) + .then((backgroundColor: any) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.TEXT), + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "color", + textColor, + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "background", + backgroundColor, + ); + }); + }); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div", + "font-family", + "Inter", + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "font-size", + "24px", + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "font-style", + "italic", + ); + agHelper.AssertAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "textalign", + "LEFT", + ); + }); + + it("7. Pick color using Full color picker", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.ToggleJSMode("Background color", false); + propPane.ToggleJSMode("Text color", false); + propPane.TogglePropertyState("Full color picker", "On"); + agHelper.GetNClick(propPane._propertyControlColorPicker("textcolor")); + agHelper.GetNClick(propPane._propertyControlColorPicker("backgroundcolor")); + agHelper.GetNClick(propPane._propertyControlColorPicker("bordercolor")); + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "color", + ) + .then((textColor: any) => { + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer + " > div > div", + "background", + ) + .then((backgroundColor: any) => { + agHelper + .GetWidgetCSSFrAttribute( + widgetLocators.textWidgetContainer, + "border-color", + ) + .then((borderColor: any) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.TEXT), + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "color", + textColor, + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer + " > div > div", + "background", + backgroundColor, + ); + agHelper.AssertCSS( + widgetLocators.textWidgetContainer, + "border-color", + borderColor, + ); + }); + }); + }); + }); + + it("8. Validate renaming, duplication(copy, paste) & deletion of text widget", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Text1", "Widgets"); + + //Rename widget + propPane.RenameWidget("Text1", "Text_Widget"); + agHelper.AssertContains( + "Text_Widget", + "be.visible", + widgetLocators.widgetNameTag, + ); + agHelper.GetNClick(locators._widgetInCanvas(draggableWidgets.TEXT)); + + //Duplicate with hotkeys + entityExplorer.CopyPasteWidget("Text_Widget"); + agHelper.ValidateToastMessage("Copied Text_Widget"); + agHelper.AssertContains( + "Text_WidgetCopy", + "be.visible", + widgetLocators.widgetNameTag, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.TEXT)) + .should("have.length", 2); + deployMode.NavigateBacktoEditor(); + + //Duplicate from property pane + entityExplorer.SelectEntityByName("Text_WidgetCopy", "Widgets"); + propPane.CopyPasteWidgetFromPropertyPane("Text_WidgetCopy"); + agHelper.ValidateToastMessage("Copied Text_WidgetCopy"); + agHelper.AssertContains( + "Text_WidgetCopyCopy", + "be.visible", + widgetLocators.widgetNameTag, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.TEXT)) + .should("have.length", 3); + deployMode.NavigateBacktoEditor(); + + //Delete widget from property pane + propPane.DeleteWidgetFromPropertyPane("Text_WidgetCopyCopy"); + + //Delete widget using hotkeys + entityExplorer.SelectEntityByName("Text_WidgetCopy", "Widgets"); + agHelper.PressDelete(); + agHelper.AssertContains( + "Text_WidgetCopyCopy", + "not.exist", + widgetLocators.widgetNameTag, + ); + agHelper.AssertContains( + "Text_WidgetCopy", + "not.exist", + widgetLocators.widgetNameTag, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TEXT)); + agHelper + .GetElement(locators._widgetInDeployed(draggableWidgets.TEXT)) + .should("have.length", 1); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Text/Text_new_feature_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Text/Text_new_feature_spec.js index 2014f85d0e..85ea268ea3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Text/Text_new_feature_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Text/Text_new_feature_spec.js @@ -1,10 +1,14 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); const widgetsPage = require("../../../../../locators/Widgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import { + agHelper, + deployMode, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; describe("Text Widget color/font/alignment Functionality", function () { before(() => { - _.agHelper.AddDsl("textDsl"); + agHelper.AddDsl("textDsl"); }); beforeEach(() => { @@ -56,11 +60,11 @@ describe("Text Widget color/font/alignment Functionality", function () { this.dataSet.TextLabelValueScrollable, ); cy.wait("@updateLayout"); - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.get(commonlocators.headingTextStyle) .should("have.text", this.dataSet.TextLabelValueScrollable) .should("have.css", "font-size", "16px"); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); it("3. Test to validate text format", function () { @@ -86,10 +90,8 @@ describe("Text Widget color/font/alignment Functionality", function () { cy.wait(500); cy.wait("@updateLayout"); cy.readTextDataValidateCSS("color", "rgb(219, 234, 254)"); - cy.get(widgetsPage.textColor) - .clear({ force: true }) - .type("purple", { force: true }); - cy.wait("@updateLayout"); + propPane.EnterJSContext("Text color", "purple"); + agHelper.Sleep(1000); cy.readTextDataValidateCSS("color", "rgb(128, 0, 128)"); //Checks the cell background with color picker @@ -109,10 +111,7 @@ describe("Text Widget color/font/alignment Functionality", function () { ); //Toggle JS check with cell background: - cy.get(widgetsPage.cellBackgroundToggle).click({ force: true }); - cy.updateCodeInput(widgetsPage.cellBackground, "purple"); - - cy.wait("@updateLayout"); + propPane.EnterJSContext("Background color", "purple"); cy.readTextDataValidateCSS("color", "rgb(128, 0, 128)"); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_TreeSelect_MultiSelect_Empty_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Select_TreeSelect_MultiSelect_Empty_spec.ts similarity index 76% rename from app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_TreeSelect_MultiSelect_Empty_spec.js rename to app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Select_TreeSelect_MultiSelect_Empty_spec.ts index 11e3c24f7b..e17ac3ac03 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_TreeSelect_MultiSelect_Empty_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Select_TreeSelect_MultiSelect_Empty_spec.ts @@ -1,17 +1,23 @@ -const formWidgetsPage = require("../../../../../locators/FormWidgets.json"); +import formWidgetsPage from "../../../../../locators/FormWidgets.json"; import * as _ from "../../../../../support/Objects/ObjectsCore"; describe("MultiSelect, Tree Select and Multi Tree Select Widget Empty Options Functionality", function () { before(() => { _.agHelper.AddDsl("SelectDslWithEmptyOptions"); }); it("1. To Check empty options for Multi Select Tree Widget", () => { - cy.get(formWidgetsPage.treeSelectInput).first().click({ force: true }); + cy.wait(1000) + .get(formWidgetsPage.treeSelectInput) + .first() + .click({ force: true }) + .wait(500); cy.get(".rc-tree-select-empty").should("have.text", "No Results Found"); //To Check empty options for Single Select Tree Widget" - cy.get(formWidgetsPage.treeSelectInput) + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) .last() .click({ force: true }) + .wait(500) .get(".single-tree-select-dropdown .rc-tree-select-empty") .should("have.text", "No Results Found"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Single_Select_Tree_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Single_Select_Tree_spec.ts similarity index 77% rename from app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Single_Select_Tree_spec.js rename to app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Single_Select_Tree_spec.ts index 4ebba2ed59..9c191593ae 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Single_Select_Tree_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Single_Select_Tree_spec.ts @@ -1,14 +1,19 @@ -const formWidgetsPage = require("../../../../../locators/FormWidgets.json"); -const publish = require("../../../../../locators/publishWidgetspage.json"); -const commonlocators = require("../../../../../locators/commonlocators.json"); -const widgetsPage = require("../../../../../locators/Widgets.json"); -import * as _ from "../../../../../support/Objects/ObjectsCore"; +import formWidgetsPage from "../../../../../locators/FormWidgets.json"; +import publish from "../../../../../locators/publishWidgetspage.json"; +import commonlocators from "../../../../../locators/commonlocators.json"; +import widgetsPage from "../../../../../locators/Widgets.json"; + +import { + agHelper, + deployMode, + propPane, +} from "../../../../../support/Objects/ObjectsCore"; const toggleJSButton = (name) => `.t--property-control-${name} .t--js-toggle`; describe("Single Select Widget Functionality", function () { before(() => { - _.agHelper.AddDsl("TreeSelectDsl"); + agHelper.AddDsl("TreeSelectDsl"); }); it("1. Check isDirty meta property", function () { @@ -19,11 +24,15 @@ describe("Single Select Widget Functionality", function () { ); // Change defaultText cy.openPropertyPane("singleselecttreewidget"); - cy.updateCodeInput(".t--property-control-defaultselectedvalue", "GREEN"); + propPane.UpdatePropertyFieldValue("Default selected value", "GREEN"); // Check if isDirty is reset to false cy.get(".t--widget-textwidget").should("contain", "false"); // Interact with UI - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(1000) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); cy.get(formWidgetsPage.treeSelectFilterInput).click().type("light"); cy.treeSelectDropdown("Light Blue"); // Check if isDirty is set to true @@ -45,14 +54,22 @@ describe("Single Select Widget Functionality", function () { }); it("3. To Validate Options", function () { - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); cy.get(formWidgetsPage.treeSelectFilterInput).click().type("light"); cy.treeSelectDropdown("Light Blue"); }); it("4. Clears the search field when widget is closed", () => { // Open the widget - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); // Search for Green option in the search input cy.get(formWidgetsPage.treeSelectFilterInput).click().type("Green"); // Select the Green Option @@ -63,7 +80,11 @@ describe("Single Select Widget Functionality", function () { .first() .should("have.text", "Green"); // Reopen the widget - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); // Assert the search input is cleared cy.get(formWidgetsPage.treeSelectFilterInput) .invoke("val") @@ -72,25 +93,29 @@ describe("Single Select Widget Functionality", function () { it("5. To Unchecked Visible Widget", function () { cy.togglebarDisable(commonlocators.visibleCheckbox); - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.get( publish.singleselecttreewidget + " " + ".rc-tree-select-single", ).should("not.exist"); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); it("6. To Check Visible Widget", function () { cy.openPropertyPane("singleselecttreewidget"); cy.togglebar(commonlocators.visibleCheckbox); - _.deployMode.DeployApp(); + deployMode.DeployApp(); cy.get( publish.singleselecttreewidget + " " + ".rc-tree-select-single", ).should("be.visible"); - _.deployMode.NavigateBacktoEditor(); + deployMode.NavigateBacktoEditor(); }); it("7. To Check Option Not Found", function () { - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); cy.get(formWidgetsPage.treeSelectFilterInput).click().type("ABCD"); cy.get(".tree-select-dropdown .rc-tree-select-empty").contains( "No Results Found", @@ -132,7 +157,11 @@ describe("Single Select Widget Functionality", function () { // Add a message to alert event in onOptionChange cy.testJsontext("onoptionchange", `{{showAlert('Option Changed')}}`); // Open the widget - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); // Search for Green option in the search input cy.get(formWidgetsPage.treeSelectFilterInput).click().type("Green"); // Select the Green Option @@ -142,7 +171,11 @@ describe("Single Select Widget Functionality", function () { // Validate the toast message cy.validateToastMessage("Option Changed"); // Open the widget - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); // Search for Green option (selecting same option) in the search input cy.get(formWidgetsPage.treeSelectFilterInput).click().type("Green"); // Select the Green Option diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Tree_Select_2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Tree_Select_2_spec.ts new file mode 100644 index 0000000000..797b3b9e2e --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Tree_Select_2_spec.ts @@ -0,0 +1,330 @@ +import { + agHelper, + locators, + deployMode, + entityExplorer, + propPane, + apiPage, + dataSources, + draggableWidgets, +} from "../../../../../support/Objects/ObjectsCore"; + +describe("Tree Select widget Tests", function () { + before(() => { + entityExplorer.DragDropWidgetNVerify("formwidget", 500, 100); + entityExplorer.DragDropWidgetNVerify("singleselecttreewidget", 350, 300); + entityExplorer.DragDropWidgetNVerify("buttonwidget", 450, 350); + }); + + let options = `[ + { + "label": "Blue", + "value": "BLUE", + "children": [ + { + "label": "Dark Blue", + "value": "DARK BLUE" + }, + { + "label": "Light Blue", + "value": "LIGHT BLUE" + } + ] + }, + { + "label": "Green", + "value": "GREEN" + }, + { + "label": "Red", + "value": "RED" + } + ]`; + + it("1. Verify required field", function () { + entityExplorer.SelectEntityByName("TreeSelect1", "Widgets"); + propPane.TogglePropertyState("required", "On"); + propPane.UpdatePropertyFieldValue("Default selected value", ""); + agHelper.AssertElementEnabledDisabled(locators._buttonInDeployedMode, 1); + // Binding with Button + propPane.ToggleJSMode("required", true); + propPane.UpdatePropertyFieldValue( + "Required", + "{{Button3.isDisabled?false:true}}", + ); + entityExplorer.SelectEntityByName("Button3", "Widgets"); + propPane.TogglePropertyState("disabled", "On"); + agHelper.AssertElementEnabledDisabled( + locators._buttonInDeployedMode, + 1, + false, + ); + propPane.TogglePropertyState("disabled", "Off"); + agHelper.AssertElementEnabledDisabled( + locators._buttonInDeployedMode, + 1, + true, + ); + }); + + it("2. Verify placeholder", function () { + entityExplorer.SelectEntityByName("TreeSelect1", "Widgets"); + propPane.UpdatePropertyFieldValue("Options", ""); + propPane.UpdatePropertyFieldValue("Placeholder", "Select new option"); + agHelper.AssertText( + locators._treeSelectPlaceholder, + "text", + "Select new option", + ); + // Binding with Text widget + entityExplorer.DragDropWidgetNVerify("textwidget", 550, 500); + propPane.UpdatePropertyFieldValue("Text", "Select value"); + entityExplorer.SelectEntityByName("TreeSelect1", "Widgets"); + propPane.UpdatePropertyFieldValue("Placeholder", "{{Text2.text}}"); + agHelper.AssertText( + locators._treeSelectPlaceholder, + "text", + "Select value", + ); + }); + + it("3. Verify expand all by default", function () { + propPane.UpdatePropertyFieldValue("Options", options); + propPane.TogglePropertyState("expandallbydefault", "On"); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.TREESELECT)); + agHelper.AssertElementExist(locators._dropDownMultiTreeValue("Dark Blue")); + }); + + it("4. Verify Full color picker and font size", () => { + // Verify font color picker opens up + propPane.MoveToTab("Style"); + agHelper.GetNClick(propPane._propertyControlColorPicker("fontcolor")); + agHelper.AssertElementVisibility(propPane._colorPickerV2Color); + // Verify full color picker + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "text", 0); + propPane.TogglePropertyState("fontcolor", "On", ""); + agHelper.AssertAttribute(propPane._colorPickerInput, "type", "color", 0); + // Font size + propPane.SelectPropertiesDropDown("fontsize", "L"); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "L"); + propPane.ToggleJSMode("fontsize", true); + propPane.UpdatePropertyFieldValue("Font size", "1rem"); + propPane.ToggleJSMode("fontsize", false); + propPane.AssertPropertiesDropDownCurrentValue("fontsize", "M"); + // Verify Emphasis + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + agHelper.AssertAttribute(locators._label, "font-style", "BOLD"); + agHelper.GetNClick(propPane._emphasisSelector("BOLD")); + propPane.ToggleJSMode("emphasis", true); + propPane.UpdatePropertyFieldValue("Emphasis", "ITALIC"); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + + // Preview mode + agHelper.GetNClick(locators._enterPreviewMode); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + agHelper.GetNClick(locators._exitPreviewMode); + + // Deploy mode + deployMode.DeployApp(); + agHelper.AssertAttribute(locators._label, "font-style", "ITALIC"); + deployMode.NavigateBacktoEditor(); + + // entityExplorer.SelectEntityByName("Form1"); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.MoveToTab("Style"); + + // Verify border + agHelper.GetNClick(propPane._segmentedControl("0px")); + agHelper.AssertCSS(".rc-tree-select", "border-radius", "0px"); + }); + + it("5. Verify Api binding", () => { + apiPage.CreateAndFillApi("https://mock-api.appsmith.com/users"); + apiPage.RunAPI(); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.MoveToTab("Content"); + propPane.UpdatePropertyFieldValue( + "Options", + `{{Api1.data.users.map((s)=>{return{"label":s.name,"value":s.name}})}}`, + ); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.AssertElementExist(locators._treeSelectTitle); + }); + + it("6. Verify onOptionChange with query", () => { + entityExplorer.DragDropWidgetNVerify("checkboxwidget", 300, 600); + entityExplorer.DragDropWidgetNVerify("inputwidgetv2", 500, 700); + entityExplorer.DragDropWidgetNVerify("iframewidget", 550, 800); + // Execute the query + let postgresDatasourceName: any; + dataSources.StartDataSourceRoutes(); + agHelper + .GetElement(locators._newDataSourceBtn) + .last() + .click({ force: true }); + dataSources.NavigateToDSCreateNew(); + dataSources.CreatePlugIn("PostgreSQL"); + agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + postgresDatasourceName = uid; + agHelper.GetNClick(locators._dsName); + agHelper.TypeText(locators._dsNameTxt, postgresDatasourceName); + dataSources.FillPostgresDSForm(); + dataSources.SaveDatasource(); + dataSources.NavigateFromActiveDS(postgresDatasourceName, true); + }); + dataSources.RunQuery(); + + entityExplorer.SelectEntityByName("TreeSelect1", "Widgets"); + propPane.UpdatePropertyFieldValue("Options", options); + propPane.SelectPlatformFunction("onOptionChange", "Execute a query"); + agHelper.GetNClick(`${locators._dropDownValue("Query1")}`, 0, true); + agHelper.GetNClick(locators._callbackAddBtn, 0, true); + agHelper.GetNClick(locators._dropDownValue("Show alert")); + agHelper.TypeText( + propPane._actionSelectorFieldByLabel("Message"), + "Success", + ); + agHelper.GetNClick(propPane._actionSelectorPopupClose); + deployMode.DeployApp(); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Green")); + agHelper.ValidateToastMessage("Success"); + }); + + it("7. Verify onOptionChange with Navigate To", () => { + deployMode.NavigateBacktoEditor(); + // Navigate To + entityExplorer.SelectEntityByName("Form1", "Widgets"); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.ToggleJSMode("onOptionChange", true); + propPane.UpdatePropertyFieldValue( + "onOptionChange", + "{{navigateTo('www.yahoo.com', {}, 'SAME_WINDOW');}}", + ); + deployMode.DeployApp(); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Red")); + agHelper.AssertURL("yahoo.com"); + agHelper.BrowserNavigation(-1); + }); + + it("8. Verify onOptionChange with Alert", () => { + deployMode.NavigateBacktoEditor(); + // Alert + entityExplorer.SelectEntityByName("Form1", "Widgets"); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.UpdatePropertyFieldValue( + "onOptionChange", + "{{showAlert('Option Changed', '');}}", + ); + deployMode.DeployApp(); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Green")); + agHelper.ValidateToastMessage("Option Changed"); + }); + + it("9. Verify onOptionChange with download", () => { + deployMode.NavigateBacktoEditor(); + // Download + entityExplorer.SelectEntityByName("Form1", "Widgets"); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.UpdatePropertyFieldValue( + "onOptionChange", + `{{download('https://assets.codepen.io/3/kiwi.svg', 'kiwi.svg', 'image/svg+xml').then(() => { + showAlert('Download Success', ''); + });}}`, + ); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Red")); + agHelper.ValidateToastMessage("Download Success"); + }); + + it("10. Verify onOptionChange with Reset", () => { + // Reset Widget + entityExplorer.SelectEntityByName("Form1", "Widgets"); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.UpdatePropertyFieldValue( + "onOptionChange", + '{{resetWidget("Checkbox1", true);}}', + ); + deployMode.DeployApp(); + agHelper.GetNClick(`${locators._widgetInDeployed("checkbox1")}`); + agHelper.AssertExistingCheckedState( + locators._checkboxInDeployedMode, + "false", + ); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Green")); + agHelper.AssertExistingCheckedState(locators._checkboxInDeployedMode); + }); + + it("11. Verify onOptionChange with Modal", () => { + deployMode.NavigateBacktoEditor(); + // Modal + entityExplorer.SelectEntityByName("Form1", "Widgets"); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.ToggleJSMode("onOptionChange", false); + propPane.SelectPlatformFunction("onOptionChange", "Show modal"); + agHelper.GetNClick(propPane._actionOpenDropdownSelectModal); + agHelper.GetNClick(propPane._createModalButton); + agHelper.AssertElementVisibility(locators._modal); + agHelper.GetNClick(locators._closeModal, 0, true); + deployMode.DeployApp(); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Red")); + agHelper.AssertElementVisibility(locators._modal); + agHelper.GetNClick(locators._closeModal, 0, true); + agHelper.Sleep(3000); + agHelper.AssertElementAbsence(locators._modal); + }); + + it("12. Verify onOptionChange with iframe", () => { + deployMode.NavigateBacktoEditor(); + // Postmessage on iframe + entityExplorer.SelectEntityByName("Iframe1", "Widgets"); + propPane.UpdatePropertyFieldValue( + "srcDoc", + `
    + + `, + ); + entityExplorer.SelectEntityByName("Form1", "Widgets"); + entityExplorer.SelectEntityByName("TreeSelect1", "Form1"); + propPane.ToggleJSMode("onOptionChange", true); + propPane.UpdatePropertyFieldValue( + "onOptionChange", + `{{postWindowMessage('Test', 'Iframe1', "*");}}`, + ); + deployMode.DeployApp(); + agHelper.GetNClick( + `${locators._widgetInDeployed("singleselecttreewidget")}`, + ); + agHelper.GetNClick(locators._dropDownMultiTreeValue("Green")); + + agHelper.GetElement('iframe[id="iframe-Iframe1"]').then(($iframe) => { + const iframe = $iframe.contents(); + + cy.wrap(iframe).find("#target").should("have.text", "Test"); + }); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Tree_Select_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Tree_Select_spec.ts similarity index 90% rename from app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Tree_Select_spec.js rename to app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Tree_Select_spec.ts index 32e87b26b1..21c9ff2cd0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Tree_Select_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TreeSelect/Tree_Select_spec.ts @@ -1,6 +1,6 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; -const explorer = require("../../../../../locators/explorerlocators.json"); -const formWidgetsPage = require("../../../../../locators/FormWidgets.json"); +import explorer from "../../../../../locators/explorerlocators.json"; +import formWidgetsPage from "../../../../../locators/FormWidgets.json"; describe("Tree Select Widget", function () { before(() => { @@ -32,7 +32,11 @@ describe("Tree Select Widget", function () { .invoke("val") .should("be.empty"); // click on the widget - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); // select Green option cy.treeSelectDropdown("Green"); // again click on cancel icon in the widget @@ -56,7 +60,11 @@ describe("Tree Select Widget", function () { .find(".rc-tree-select-clear") .should("not.exist"); // click on the widget again - cy.get(formWidgetsPage.treeSelectInput).last().click({ force: true }); + cy.wait(500) + .get(formWidgetsPage.treeSelectInput) + .last() + .click({ force: true }) + .wait(500); // select Green option cy.treeSelectDropdown("Green"); // assert if the widget input value is Green diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Video/Video2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Video/Video2_Spec.ts new file mode 100644 index 0000000000..1d02dfc036 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Video/Video2_Spec.ts @@ -0,0 +1,262 @@ +import { + agHelper, + draggableWidgets, + deployMode, + entityExplorer, + homePage, + locators, + propPane, + theme, + widgetLocators, +} from "../../../../../support/Objects/ObjectsCore"; +import testdata from "../../../../../fixtures/testdata.json"; + +describe("Video widget tests", function () { + before(() => { + homePage.NavigateToHome(); + //Contains video widget expanded to specific size such that all the buttons in it are visible & camera widget(video) + homePage.ImportApp("videoWidgetApp.json"); + }); + + it("1. Verify Basic Functionality of Video Widget - paused, ended", function () { + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + //Play , Pause & Resume Video + agHelper.GetElement(widgetLocators.video).then(($video) => { + $video[0].play(); + //Validate video parsed on clicking play + const attrValue = $video[0].webkitVideoDecodedByteCount; + expect(attrValue).be.greaterThan(30000); + }); + agHelper.AssertProperty(widgetLocators.video, "paused", false); + agHelper.AssertProperty(widgetLocators.video, "ended", false); + agHelper.GetElement(widgetLocators.video).then(($video) => { + $video[0].pause(); + }); + agHelper.AssertProperty(widgetLocators.video, "paused", true); + //Change playback speed & seek + agHelper.GetElement(widgetLocators.video).then(($video) => { + $video[0].playbackRate = 4; + $video[0].play(); + }); + //Wait for video to end + agHelper.Sleep(5000); + agHelper.AssertProperty(widgetLocators.video, "ended", true); + }); + + it("2. Verify Basic Functionality of Video Widget - muted", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + //Validate video for youtube url + propPane.TypeTextIntoField("URL", testdata.videoUrl); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.Sleep(2000); + agHelper.GetElement(widgetLocators.iFrame).then(($iframe) => { + const doc = $iframe.contents(); + const video = doc.find(widgetLocators.video); + //Check play, mute & unmute, volume buttons + cy.wrap(doc.find(widgetLocators.videoWidgetYoutubeLargePlayBtn)).click(); + cy.wrap(video).click(); + agHelper.Sleep(1000); + cy.wrap(doc.find(widgetLocators.videoWidgetYoutubeMuteBtn)).click(); + agHelper.AssertProperty(video, "muted", true); + agHelper.AssertProperty(video, "paused", true); + cy.wrap(doc.find(widgetLocators.videoWidgetYoutubeVolumeBtn)).type( + "{rightarrow}{rightarrow}", + ); + agHelper.AssertProperty(video, "muted", false); + }); + }); + + it("3. Verify widget for invalid URL's", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + propPane.RemoveText("URL"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.AssertContains("Please provide a valid url"); + agHelper.AssertElementAbsence( + locators._widgetInDeployed(draggableWidgets.VIDEO) + + " " + + widgetLocators.video, + ); + + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + //Check for Non-video url + propPane.TypeTextIntoField( + "URL", + "https://www.pexels.com/photo/closeup-photo-of-brown-brick-wall-1227511/", + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.GetElement(widgetLocators.video).then(($video) => { + $video[0].play(); + const videoValue = $video[0].webkitVideoDecodedByteCount; + const audioValue = $video[0].webkitAudioDecodedByteCount; + expect($video[0].videoHeight).be.equal(0); + expect($video[0].videoWidth).be.equal(0); + expect(videoValue).be.equal(0); + expect(audioValue).be.equal(0); + }); + }); + + it("4. Verify auto play property", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + agHelper.AssertExistingToggleState("Autoplay", "false"); + propPane.TypeTextIntoField("URL", testdata.videoUrl2); + propPane.EnterJSContext("Autoplay", "{{(45>55)?false:true}}", true, true); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.AssertProperty(widgetLocators.video, "paused", false); + agHelper.GetElement(widgetLocators.video).then(($video) => { + const attrValue = $video[0].webkitVideoDecodedByteCount; + expect(attrValue).be.greaterThan(30000); + }); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + propPane.EnterJSContext("Autoplay", "", false); + propPane.ToggleJSMode("Autoplay", false); + propPane.TogglePropertyState("Autoplay", "Off"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.AssertProperty(widgetLocators.video, "paused", true); + }); + + it("5. Verify visible property", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + agHelper.AssertExistingToggleState("Visible", "true"); + propPane.EnterJSContext("Visible", "{{(55>45)?false:true}}", true, true); + deployMode.DeployApp(); + agHelper.AssertElementAbsence( + locators._widgetInDeployed( + locators._widgetInDeployed(draggableWidgets.VIDEO) + + " " + + widgetLocators.video, + ), + ); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + propPane.EnterJSContext("Visible", "", false); + propPane.ToggleJSMode("Visible", false); + propPane.TogglePropertyState("Visible", "On"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.AssertElementVisibility( + locators._widgetInDeployed(draggableWidgets.VIDEO) + + " " + + widgetLocators.video, + ); + }); + + it("6. Verify OnPlay, OnPause, OnEnd events are JS convertible", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + propPane.EnterJSContext( + "onPlay", + "{{showAlert('Video is playing!')}}", + true, + true, + ); + propPane.EnterJSContext( + "onPause", + "{{showAlert('Video paused!')}}", + true, + true, + ); + propPane.EnterJSContext( + "onEnd", + "{{showAlert('Video ended!')}}", + true, + true, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + agHelper.GetElement(widgetLocators.video).then(($video) => { + $video[0].play(); + agHelper.ValidateToastMessage("Video is playing!"); + agHelper.Sleep(3000); + }); + agHelper.GetElement(widgetLocators.video).then(($video) => { + $video[0].pause(); + agHelper.ValidateToastMessage("Video paused!"); + }); + agHelper.GetElement(widgetLocators.video).then(($video) => { + $video[0].play(); + //Wait for video to end + agHelper.Sleep(5000); + agHelper.ValidateToastMessage("Video ended!"); + }); + }); + + it("7. Verify video styles", function () { + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Video1", "Widgets"); + propPane.MoveToTab("Style"); + propPane.SelectColorFromColorPicker("backgroundcolor", 9); + agHelper.ContainsNClick("Medium"); + propPane.EnterJSContext("Border radius", "1.5rem"); + agHelper + .GetWidgetCSSFrAttribute(widgetLocators.video, "background-color") + .then((backgroundcolor) => { + deployMode.DeployApp( + locators._widgetInDeployed(draggableWidgets.VIDEO), + ); + agHelper.AssertCSS( + widgetLocators.video, + "background-color", + backgroundcolor, + ); + }); + agHelper.AssertCSS( + widgetLocators.video, + "box-shadow", + "rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px", + ); + agHelper.AssertCSS(widgetLocators.video, "border-radius", "24px"); + }); + + //Skipping below test due to issue - https://github.com/appsmithorg/appsmith/issues/26166 + // it("8. Verify Camera Binding", function () { + // deployMode.NavigateBacktoEditor(); + // entityExplorer.SelectEntityByName("Camera1", "Widgets"); + // propPane.AssertPropertiesDropDownCurrentValue( + // "Default mobile camera", + // "Back (Rear)", + // ); + // entityExplorer.SelectEntityByName("Video1", "Widgets"); + // propPane.TypeTextIntoField("URL", "{{Camera1.videoBlobURL}}"); + // propPane.TogglePropertyState("Autoplay", "On"); + // agHelper.AssertExistingToggleState("Visible", "true"); + // deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + // agHelper.AssertElementVisibility( + // locators._widgetInDeployed(draggableWidgets.VIDEO) + + // " " + + // widgetLocators.video, + // ); + // agHelper.AssertProperty(widgetLocators.video, "paused", false); + // agHelper.ValidateToastMessage("Video is playing!"); + // agHelper.GetElement(widgetLocators.video).then(($video) => { + // $video[0].pause(); + // agHelper.ValidateToastMessage("Video paused!"); + // }); + + // deployMode.NavigateBacktoEditor(); + // entityExplorer.SelectEntityByName("Camera1", "Widgets"); + // propPane.SelectPropertiesDropDown( + // "Default mobile camera", + // "Front (Selfie)", + // ); + // entityExplorer.SelectEntityByName("Video1", "Widgets"); + // propPane.TogglePropertyState("Autoplay", "On"); + // agHelper.AssertExistingToggleState("Visible", "true"); + // deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.VIDEO)); + // agHelper.AssertElementVisibility( + // locators._widgetInDeployed(draggableWidgets.VIDEO) + + // " " + + // widgetLocators.video, + // ); + // agHelper.AssertProperty(widgetLocators.video, "paused", false); + // agHelper.ValidateToastMessage("Video is playing!"); + // agHelper.GetElement(widgetLocators.video).then(($video) => { + // $video[0].pause(); + // agHelper.ValidateToastMessage("Video paused!"); + // }); + // }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/Video_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Video/Video_spec.ts similarity index 97% rename from app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/Video_spec.js rename to app/client/cypress/e2e/Regression/ClientSide/Widgets/Video/Video_spec.ts index 30bc871637..4bfba3354b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Others/Video_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Video/Video_spec.ts @@ -9,7 +9,7 @@ import { describe("Video Widget Functionality", function () { before(() => { - agHelper.AddDsl("videoWidgetDsl"); + entityExplorer.DragNDropWidget(draggableWidgets.VIDEO); }); it("1. Video Widget play functionality validation", function () { @@ -72,12 +72,12 @@ describe("Video Widget Functionality", function () { it("4. Checks if video widget is reset on button click", function () { propPane.UpdatePropertyFieldValue("URL", testdata.videoUrl2); - entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 200, 200); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 200, 400); cy.selectResetWidget("onClick"); cy.selectWidgetForReset("Video1"); - entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 300, 300); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 300, 600); propPane.UpdatePropertyFieldValue("Text", "{{Video1.playState}}"); agHelper.Sleep(1500); // Wait time added for the widget to load current video state diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateAppWithSameNameInWorkspace_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateAppWithSameNameInWorkspace_spec.js index 5564a6cdc0..96d0e87011 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateAppWithSameNameInWorkspace_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateAppWithSameNameInWorkspace_spec.js @@ -3,6 +3,7 @@ import homePage from "../../../../locators/HomePage"; import { REPO, CURRENT_REPO } from "../../../../fixtures/REPO"; const application = require("../../../../locators/Applications.json"); import * as _ from "../../../../support/Objects/ObjectsCore"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; describe("Create workspace and a new app / delete and recreate app", function () { let workspaceId; @@ -13,6 +14,8 @@ describe("Create workspace and a new app / delete and recreate app", function () cy.get("@guid").then((uid) => { workspaceId = uid; appid = uid; + featureFlagIntercept({ license_gac_enabled: true }); + cy.wait(2000); _.homePage.CreateNewWorkspace(uid); //Automated as part of Bug19506 cy.get(application.shareButton).first().click({ force: true }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateSameAppInDiffWorkspace_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateSameAppInDiffWorkspace_spec.js index eb403c18a3..d03ea962d5 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateSameAppInDiffWorkspace_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/CreateSameAppInDiffWorkspace_spec.js @@ -3,6 +3,7 @@ import homePage from "../../../../locators/HomePage"; import { REPO, CURRENT_REPO } from "../../../../fixtures/REPO"; const application = require("../../../../locators/Applications.json"); import * as _ from "../../../../support/Objects/ObjectsCore"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; describe("Create app same name in different workspace", function () { let workspaceId; @@ -14,7 +15,6 @@ describe("Create app same name in different workspace", function () { cy.generateUUID().then((uid) => { workspaceId = uid; appid = uid; - localStorage.setItem("WorkspaceName", workspaceId); cy.createWorkspace(); cy.wait("@createWorkspace").then((interception) => { newWorkspaceName = interception.response.body.data.name; @@ -32,6 +32,8 @@ describe("Create app same name in different workspace", function () { "response.body.responseMeta.status", 200, ); + featureFlagIntercept({ license_gac_enabled: true }); + cy.wait(2000); const newWSName = workspaceId + "1"; //Automated as part of Bug19506 cy.get(".t--applications-container") diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/DeleteMultipleApplications.ts b/app/client/cypress/e2e/Regression/ClientSide/Workspace/DeleteMultipleApplications.ts new file mode 100644 index 0000000000..b2a4ad97dc --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/DeleteMultipleApplications.ts @@ -0,0 +1,128 @@ +import { + agHelper, + homePage, + assertHelper, + inviteModal, +} from "../../../../support/Objects/ObjectsCore"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; + +const timestamp = Date.now(); + +const MultipleDeleteFirstWorkspace = { + workspaceName: `workspace_${timestamp}_1`, + applicationName: `app_${timestamp}_1`, +}; + +const MultipleDeleteSecondWorkspace = { + workspaceName: `workspace_${timestamp}_2`, + applicationName: `app_${timestamp}_2`, +}; + +const UnableToDeleteWorkspace = { + workspaceName: `workspace_${timestamp}_3`, + applicationName: `app_${timestamp}_3`, +}; + +describe("Delete multiple application", function () { + before(() => { + homePage.CreateNewWorkspace( + MultipleDeleteFirstWorkspace.workspaceName, + true, + ); + homePage.CreateAppInWorkspace( + MultipleDeleteFirstWorkspace.workspaceName, + MultipleDeleteFirstWorkspace.applicationName, + ); + + homePage.CreateNewWorkspace( + MultipleDeleteSecondWorkspace.workspaceName, + true, + ); + homePage.CreateAppInWorkspace( + MultipleDeleteSecondWorkspace.workspaceName, + MultipleDeleteSecondWorkspace.applicationName, + ); + }); + + it("1. Should select & cancel delete multiple applications in different workspace & other action items should not be visible when selection mode is on", function () { + homePage.NavigateToHome(); + homePage.SelectMultipleApplicationToDelete( + MultipleDeleteFirstWorkspace.applicationName, + ); + homePage.SelectMultipleApplicationToDelete( + MultipleDeleteSecondWorkspace.applicationName, + ); + + // Asserting all the other share & create new app button not visible + agHelper.AssertElementVisibility( + homePage._shareWorkspace(MultipleDeleteFirstWorkspace.workspaceName), + false, + ); + + agHelper.AssertElementVisibility( + homePage._existingWorkspaceCreateNewApp( + MultipleDeleteFirstWorkspace.workspaceName, + ), + false, + ); + + agHelper.ClickButton("Cancel"); + agHelper.AssertElementAbsence(homePage._multipleSelectedApplication); + agHelper.AssertElementExist( + homePage._appCard(MultipleDeleteFirstWorkspace.applicationName), + ); + agHelper.AssertElementExist( + homePage._appCard(MultipleDeleteSecondWorkspace.applicationName), + ); + }); + + it("2. Should select & delete multiple applications in different workspace", function () { + homePage.SelectMultipleApplicationToDelete( + MultipleDeleteFirstWorkspace.applicationName, + ); + homePage.SelectMultipleApplicationToDelete( + MultipleDeleteSecondWorkspace.applicationName, + ); + agHelper.ClickButton("Delete"); + agHelper.ClickButton("Yes"); + assertHelper.WaitForNetworkCall("@deleteMultipleApp").then((response) => { + expect(response?.body?.data?.length).to.be.equal(2); + agHelper.AssertElementAbsence( + homePage._appCard(MultipleDeleteFirstWorkspace.applicationName), + ); + agHelper.AssertElementAbsence( + homePage._appCard(MultipleDeleteSecondWorkspace.applicationName), + ); + }); + }); + + it("3. Unable to select to multiple delete if not enough permissions to delete", function () { + featureFlagIntercept({ license_gac_enabled: true }); + cy.wait(2000); + homePage.CreateNewWorkspace(UnableToDeleteWorkspace.workspaceName); + homePage.CreateAppInWorkspace( + UnableToDeleteWorkspace.workspaceName, + UnableToDeleteWorkspace.applicationName, + ); + + agHelper.GetNClick(inviteModal.locators._shareButton, 0, true); + homePage.InviteUserToApplication( + Cypress.env("TESTUSERNAME1"), + "App Viewer", + ); + homePage.LogOutviaAPI(); + + homePage.LogintoApp( + Cypress.env("TESTUSERNAME1"), + Cypress.env("TESTPASSWORD1"), + "App Viewer", + ); + + homePage.SelectMultipleApplicationToDelete( + UnableToDeleteWorkspace.applicationName, + ); + agHelper.ValidateToastMessage( + "You don't have permission to delete this application", + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/DeleteWorkspace_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Workspace/DeleteWorkspace_spec.ts index 1bb17ae9ed..214fdc11b7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/DeleteWorkspace_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/DeleteWorkspace_spec.ts @@ -1,3 +1,4 @@ +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import { agHelper, locators, @@ -24,6 +25,10 @@ describe("Delete workspace test spec", function () { it("2. Should show option to delete workspace for an admin user", function () { agHelper.VisitNAssert("/applications", "getReleaseItems"); agHelper.Sleep(2000); + + featureFlagIntercept({ license_gac_enabled: true }); + agHelper.Sleep(2000); + agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { newWorkspaceName = uid; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/LeaveWorkspaceTest_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Workspace/LeaveWorkspaceTest_spec.js index e00f24367d..a7926213a7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/LeaveWorkspaceTest_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/LeaveWorkspaceTest_spec.js @@ -1,5 +1,7 @@ /// import { agHelper, homePage } from "../../../../support/Objects/ObjectsCore"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; + describe("Leave workspace test spec", function () { let newWorkspaceName; @@ -23,6 +25,8 @@ describe("Leave workspace test spec", function () { it("2. Bug 17235 & 17987 - Non admin users can only access leave workspace popup menu validation", function () { agHelper.VisitNAssert("/applications", "getReleaseItems"); + featureFlagIntercept({ license_gac_enabled: true }); + cy.wait(2000); agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { newWorkspaceName = "LeaveWorkspace" + uid; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/LoginFromUIApp_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Workspace/LoginFromUIApp_spec.js index 6bbf12b182..dd30ee55b7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/LoginFromUIApp_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/LoginFromUIApp_spec.js @@ -2,15 +2,10 @@ import { entityExplorer, entityItems, } from "../../../../support/Objects/ObjectsCore"; -let pageid; -describe("Login from UI and check the functionality", function () { - it("1. Login/create page/delete page/delete app from UI", function () { - const appname = localStorage.getItem("AppName"); - cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); - cy.SearchApp(appname); - cy.get("#loading").should("not.exist"); - //cy.wait(5000); +describe("Create page & delete page from UI", function () { + let pageid; + it("1. Create page & delete page from UI", function () { cy.generateUUID().then((uid) => { pageid = uid; cy.Createpage(pageid); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts index ec1b471393..490d5cdd15 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts @@ -1,5 +1,6 @@ import { REPO, CURRENT_REPO } from "../../../../fixtures/REPO"; import HomePage from "../../../../locators/HomePage"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import * as _ from "../../../../support/Objects/ObjectsCore"; let workspaceId: any, appid: any; @@ -10,7 +11,8 @@ describe("Create new workspace and invite user & validate all roles", () => { cy.get("@guid").then((uid) => { workspaceId = uid; appid = uid; - //localStorage.setItem("WorkspaceName", workspaceId); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.CreateNewWorkspace(workspaceId); _.homePage.CheckWorkspaceShareUsersCount(workspaceId, 1); _.homePage.InviteUserToWorkspaceErrorMessage(workspaceId, "abcdef"); @@ -20,7 +22,7 @@ describe("Create new workspace and invite user & validate all roles", () => { Cypress.env("TESTUSERNAME1"), "App Viewer", ); - _.agHelper.GetNClick(_.homePage._visibleTextSpan("Manage Users")); + _.agHelper.GetNClick(_.homePage._visibleTextSpan("Manage users")); _.homePage.NavigateToHome(); _.homePage.CheckWorkspaceShareUsersCount(workspaceId, 2); _.homePage.CreateAppInWorkspace(workspaceId, appid); @@ -30,9 +32,11 @@ describe("Create new workspace and invite user & validate all roles", () => { it("2. Login as Administrator and search for users using search bar", () => { _.homePage.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); _.agHelper.GetNClick(_.homePage._shareWorkspace(workspaceId)); - _.agHelper.GetNClick(_.homePage._visibleTextSpan("Manage Users")); + _.agHelper.GetNClick(_.homePage._visibleTextSpan("Manage users")); cy.get(".search-highlight").should("not.exist"); _.agHelper.TypeText( _.homePage._searchUsersInput, @@ -50,6 +54,8 @@ describe("Create new workspace and invite user & validate all roles", () => { Cypress.env("TESTPASSWORD1"), "App Viewer", ); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); cy.get(_.homePage._applicationCard).first().trigger("mouseover"); cy.get(_.homePage._appHoverIcon("edit")).should("not.exist"); @@ -69,6 +75,8 @@ describe("Create new workspace and invite user & validate all roles", () => { it("4. Login as Workspace owner and Update the Invited user role to Developer", function () { _.homePage.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); _.homePage.UpdateUserRoleInWorkspace( workspaceId, @@ -85,6 +93,8 @@ describe("Create new workspace and invite user & validate all roles", () => { Cypress.env("TESTPASSWORD1"), "Developer", ); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); cy.get(_.homePage._applicationCard).first().trigger("mouseover"); _.agHelper.AssertElementExist(_.homePage._appHoverIcon("edit")); @@ -113,6 +123,8 @@ describe("Create new workspace and invite user & validate all roles", () => { it("6. Login as Workspace owner and Update the Invited user role to Administrator", function () { _.homePage.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); _.homePage.UpdateUserRoleInWorkspace( workspaceId, @@ -129,6 +141,8 @@ describe("Create new workspace and invite user & validate all roles", () => { Cypress.env("TESTPASSWORD1"), "Administrator", ); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.InviteUserToWorkspace( workspaceId, Cypress.env("TESTUSERNAME2"), @@ -166,6 +180,8 @@ describe("Create new workspace and invite user & validate all roles", () => { it("8. Login as Workspace owner and verify all 3 users are present", function () { _.homePage.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); _.homePage.UpdateUserRoleInWorkspace( workspaceId, @@ -190,6 +206,8 @@ describe("Create new workspace and invite user & validate all roles", () => { Cypress.env("TESTUSERNAME1"), Cypress.env("TESTPASSWORD1"), ); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); _.homePage.LeaveWorkspace(workspaceId); _.homePage.Signout(); @@ -201,6 +219,8 @@ describe("Create new workspace and invite user & validate all roles", () => { Cypress.env("TESTPASSWORD2"), "App Viewer", ); + featureFlagIntercept({ license_gac_enabled: true }); + _.agHelper.Sleep(2000); _.homePage.FilterApplication(appid, workspaceId); _.homePage.LeaveWorkspace(workspaceId); _.homePage.LogOutviaAPI(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts index de0a6833ac..5c87fc0eaf 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts @@ -5,9 +5,12 @@ import { homePage, assertHelper, inviteModal, + onboarding, } from "../../../../support/Objects/ObjectsCore"; import { REPO, CURRENT_REPO } from "../../../../fixtures/REPO"; +import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; +const appNavigationLocators = require("../../../../locators/AppNavigation.json"); describe("Create new workspace and share with a user", function () { let workspaceId: string, appid: string, currentUrl: any; @@ -15,6 +18,10 @@ describe("Create new workspace and share with a user", function () { it("1. Create workspace and then share with a user from Application share option within application", function () { homePage.NavigateToHome(); agHelper.Sleep(2000); + + featureFlagIntercept({ license_gac_enabled: true }); + agHelper.Sleep(2000); + agHelper.GenerateUUID(); agHelper.GetElement("@guid").then((uid) => { workspaceId = "shareApp" + uid; @@ -37,7 +44,10 @@ describe("Create new workspace and share with a user", function () { Cypress.env("TESTPASSWORD1"), "App Viewer", ); - homePage.FilterApplication(appid); + featureFlagIntercept({ license_gac_enabled: true }); + agHelper.Sleep(3000); + + homePage.FilterApplication(appid, workspaceId, false); // // eslint-disable-next-line cypress/no-unnecessary-waiting agHelper.Sleep(2000); agHelper.GetNAssertContains(homePage._appContainer, workspaceId); @@ -85,6 +95,12 @@ describe("Create new workspace and share with a user", function () { }); // comment toggle should not exist for anonymous users agHelper.AssertElementAbsence(homePage._modeSwitchToggle); + cy.get( + `${appNavigationLocators.header} ${appNavigationLocators.shareButton}`, + ) + .click() + .wait(1000); + agHelper.ClickButton("Copy application url"); }); it("5. login as uninvited user and then validate public access of Application", function () { @@ -96,6 +112,12 @@ describe("Create new workspace and share with a user", function () { agHelper.GetText(locators._emptyPageTxt).then((text) => { expect(text).to.equal("This page seems to be blank"); }); + cy.get( + `${appNavigationLocators.header} ${appNavigationLocators.shareButton}`, + ) + .click() + .wait(1000); + agHelper.ClickButton("Copy application url"); homePage.LogOutviaAPI(); }); @@ -128,4 +150,22 @@ describe("Create new workspace and share with a user", function () { assertHelper.AssertNetworkStatus("@getPagesForViewApp", 404); agHelper.AssertContains("Sign in to your account", "be.visible"); }); + + it("8. Show partner program callout when invited user is from a different domain", function () { + if (CURRENT_REPO === REPO.CE) { + agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + homePage.SignUp(`${uid}@appsmithtest.com`, uid as unknown as string); + onboarding.closeIntroModal(); + + inviteModal.OpenShareModal(); + homePage.InviteUserToApplication(`${uid}@appsmith.com`, "App Viewer"); + }); + agHelper.AssertElementVisibility( + `[data-testid="partner-program-callout"]`, + ); + + homePage.Signout(); + } + }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js index 867ed38774..3426ef0649 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js @@ -1,46 +1,55 @@ -import homePage from "../../../../locators/HomePage"; -import * as _ from "../../../../support/Objects/ObjectsCore"; +import homePageLocators from "../../../../locators/HomePage"; +import { agHelper, homePage } from "../../../../support/Objects/ObjectsCore"; describe("Workspace Import Application", function () { let workspaceId; let newWorkspaceName; - let appname; + let appname, workspaceName; before(() => { - _.agHelper.AddDsl("displayWidgetDsl"); + agHelper.AddDsl("displayWidgetDsl"); }); it("1. Can Import Application from json", function () { - _.homePage.NavigateToHome(); - appname = localStorage.getItem("AppName"); - cy.get(homePage.searchInput).type(appname); + homePage.NavigateToHome(); + workspaceName = localStorage.getItem("workspaceName"); + appname = localStorage.getItem("appName"); + + cy.get(homePageLocators.searchInput).type(workspaceName); // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(2000); - cy.get(homePage.appMoreIcon).first().click({ force: true }); - cy.get(homePage.exportAppFromMenu).click({ force: true }); - cy.get(homePage.searchInput).clear(); + cy.get(homePageLocators.appMoreIcon).first().click({ force: true }); + cy.get(homePageLocators.exportAppFromMenu).click({ force: true }); + agHelper.ValidateToastMessage("Successfully exported"); + // fetching the exported app file manually to be verified. + cy.get(homePageLocators.searchInput).clear(); cy.get(`a[id=t--export-app-link]`).then((anchor) => { const url = anchor.prop("href"); cy.request(url).then(({ body, headers }) => { expect(headers).to.have.property("content-type", "application/json"); - expect(headers).to.have.property( - "content-disposition", - `attachment; filename*=UTF-8''${appname}.json`, - ); + expect(headers) + .to.have.property("content-disposition") + .that.includes("attachment;") + .and.includes( + `filename="=?UTF-8?Q?${appname.replace(/\s/g, "_")}.json`, + ); cy.writeFile("cypress/fixtures/exported-app.json", body, "utf-8"); cy.generateUUID().then((uid) => { workspaceId = uid; - localStorage.setItem("WorkspaceName", workspaceId); cy.createWorkspace(); cy.wait("@createWorkspace").then((createWorkspaceInterception) => { newWorkspaceName = createWorkspaceInterception.response.body.data.name; - _.homePage.RenameWorkspace(newWorkspaceName, workspaceId); - cy.get(homePage.workspaceImportAppOption).click({ force: true }); + homePage.RenameWorkspace(newWorkspaceName, workspaceId); + cy.get(homePageLocators.workspaceImportAppOption).click({ + force: true, + }); - cy.get(homePage.workspaceImportAppModal).should("be.visible"); - cy.xpath(homePage.uploadLogo) + cy.get(homePageLocators.workspaceImportAppModal).should( + "be.visible", + ); + cy.xpath(homePageLocators.uploadLogo) .first() .selectFile("cypress/fixtures/exported-app.json", { force: true, @@ -51,7 +60,7 @@ describe("Workspace Import Application", function () { const { pages } = importedApp; const appSlug = importedApp.slug; let defaultPage = pages.find((eachPage) => eachPage.isDefault); - cy.get(homePage.toastMessage).should( + cy.get(homePageLocators.toastMessage).should( "contain", "Application imported successfully", ); diff --git a/app/client/cypress/e2e/Regression/ServerSide/ActionExecution/Block_Execution.ts b/app/client/cypress/e2e/Regression/ServerSide/ActionExecution/Block_Execution.ts index 33342d53cb..df1a86cde3 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/ActionExecution/Block_Execution.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/ActionExecution/Block_Execution.ts @@ -1,6 +1,7 @@ import { agHelper, apiPage, + dataManager, dataSources, } from "../../../../support/Objects/ObjectsCore"; @@ -30,7 +31,12 @@ describe("Block Action Execution when no field is present", () => { it("3. Ensure Run button is disabled for Post UQI Datasources e.g. Oracle when no body data is present", () => { let name: any; - dataSources.CreateDataSource("Oracle", true, false); + dataSources.CreateDataSource( + "Oracle", + true, + false, + dataManager.environments[1], //using staging mock data + ); cy.get("@dsName").then(($dsName) => { name = $dsName; diff --git a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_All_Verb_spec.js b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_All_Verb_spec.js index 8d13ed7704..016730d170 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_All_Verb_spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_All_Verb_spec.js @@ -23,21 +23,20 @@ describe("API Panel Test Functionality", function () { 10000, "PUT", ); - apiPage.EnterHeader(testdata.headerKey, testdata.headerValue); cy.readFile("cypress/fixtures/putjson.txt").then((json) => { apiPage.SelectPaneTab("Body"); apiPage.SelectSubTab("JSON"); dataSources.EnterQuery(json); agHelper.AssertAutoSave(); apiPage.RunAPI(); + apiPage.ResponseStatusCheck("200 OK"); cy.validateRequest( - "Api1", + "Executed successfully", testdata.baseUrl, testdata.echoMethod, testdata.Put, ); }); - cy.ResponseStatusCheck("200 OK"); cy.ResponseCheck("updatedAt"); }); @@ -48,21 +47,20 @@ describe("API Panel Test Functionality", function () { 10000, "POST", ); - apiPage.EnterHeader(testdata.headerKey, testdata.headerValue); cy.readFile("cypress/fixtures/postjson.txt").then((json) => { apiPage.SelectPaneTab("Body"); apiPage.SelectSubTab("JSON"); dataSources.EnterQuery(json); agHelper.AssertAutoSave(); apiPage.RunAPI(); + apiPage.ResponseStatusCheck("200 OK"); cy.validateRequest( - "Api1", + "Executed successfully", testdata.baseUrl, testdata.echoMethod, testdata.Post, ); }); - cy.ResponseStatusCheck("200 OK"); cy.ResponseCheck("createdAt"); }); @@ -73,21 +71,20 @@ describe("API Panel Test Functionality", function () { 10000, "PATCH", ); - apiPage.EnterHeader(testdata.headerKey, testdata.headerValue); cy.readFile("cypress/fixtures/patchjson.txt").then((json) => { apiPage.SelectPaneTab("Body"); apiPage.SelectSubTab("JSON"); dataSources.EnterQuery(json); agHelper.AssertAutoSave(); apiPage.RunAPI(); + apiPage.ResponseStatusCheck("200 OK"); cy.validateRequest( - "Api1", + "Executed successfully", testdata.baseUrl, testdata.echoMethod, testdata.Patch, ); }); - cy.ResponseStatusCheck("200 OK"); cy.ResponseCheck("updatedAt"); }); @@ -98,37 +95,36 @@ describe("API Panel Test Functionality", function () { 10000, "DELETE", ); - apiPage.EnterHeader(testdata.headerKey, testdata.headerValue); cy.readFile("cypress/fixtures/patchjson.txt").then((json) => { apiPage.SelectPaneTab("Body"); apiPage.SelectSubTab("JSON"); dataSources.EnterQuery(json); agHelper.AssertAutoSave(); apiPage.RunAPI(); + apiPage.ResponseStatusCheck("200 OK"); cy.validateRequest( - "Api1", + "Executed successfully", testdata.baseUrl, testdata.echoMethod, testdata.Delete, ); }); - cy.ResponseStatusCheck("200"); }); it("5. Test GET Action for mock API with header and pagination", function () { //const apiname = "SecondAPI"; apiPage.CreateAndFillApi(testdata.baseUrl + testdata.methods); - apiPage.EnterHeader(testdata.headerKey, testdata.headerValue); agHelper.AssertAutoSave(); apiPage.RunAPI(); + apiPage.ResponseStatusCheck("200 OK"); + cy.ResponseCheck(testdata.responsetext); cy.validateRequest( - "Api1", + "Executed successfully", testdata.baseUrl, testdata.methods, testdata.Get, ); - cy.ResponseStatusCheck(testdata.successStatusCode); - cy.ResponseCheck(testdata.responsetext); + apiPage.SelectPaneTab("Pagination"); agHelper.GetNClick(apiwidget.paginationWithUrl); cy.enterUrl( @@ -137,9 +133,15 @@ describe("API Panel Test Functionality", function () { testdata.nextUrl, ); cy.clickTest(apiwidget.TestNextUrl); - cy.validateRequest("Api1", testdata.baseUrl, testdata.next, testdata.Get); - cy.ResponseStatusCheck(testdata.successStatusCode); + apiPage.ResponseStatusCheck("200 OK"); cy.ResponseCheck("Josh M Krantz"); + cy.validateRequest( + "Executed successfully", + testdata.baseUrl, + testdata.next, + testdata.Get, + ); + apiPage.SelectPaneTab("Pagination"); cy.enterUrl( testdata.baseUrl, @@ -147,24 +149,28 @@ describe("API Panel Test Functionality", function () { testdata.prevUrl, ); cy.clickTest(apiwidget.TestPreUrl); - cy.validateRequest("Api1", testdata.baseUrl, testdata.prev, testdata.Get); - cy.ResponseStatusCheck(testdata.successStatusCode); + apiPage.ResponseStatusCheck("200 OK"); cy.ResponseCheck(testdata.responsetext); + cy.validateRequest( + "Executed successfully", + testdata.baseUrl, + testdata.prev, + testdata.Get, + ); }); it("6. API check with query params test API feature", function () { apiPage.CreateAndFillApi(testdata.baseUrl + testdata.queryAndValue); - apiPage.EnterHeader(testdata.headerKey, testdata.headerValue); agHelper.AssertAutoSave(); apiPage.RunAPI(); + apiPage.ResponseStatusCheck("200 OK"); + cy.ResponseCheck(testdata.responsetext3); cy.validateRequest( - "Api1", + "Executed successfully", testdata.baseUrl, testdata.queryAndValue, testdata.Get, ); - cy.ResponseStatusCheck("200 OK"); - cy.ResponseCheck(testdata.responsetext3); }); it("7. API check with Invalid Header", function () { @@ -172,14 +178,14 @@ describe("API Panel Test Functionality", function () { apiPage.EnterHeader(testdata.headerKey, testdata.invalidValue); agHelper.AssertAutoSave(); apiPage.RunAPI(false); + apiPage.ResponseStatusCheck("5000"); cy.validateRequest( - "Api1", + "Execution failed", testdata.baseUrl, testdata.methods, testdata.Get, true, ); - cy.ResponseStatusCheck("5000"); cy.ResponseCheck("Invalid value for Content-Type"); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts index 93e36d5df9..cc7c7e34b2 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts @@ -37,6 +37,12 @@ describe("Test API execution with dynamic binding in URL - Bug #24218", () => { "{{appsmith.store.api_url}}", "Api_with_dynamic_binding", ); + agHelper.VerifyEvaluatedValue( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl.replace( + "?records=10", + "", + ), //removing query param here due to open bug with DI team + ); apiPage.RunAPI(); apiPage.ResponseStatusCheck("200 OK"); agHelper.ActionContextMenuWithInPane({ diff --git a/app/client/cypress/e2e/Regression/ServerSide/AppLevelImport/AppImportwithDS_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/AppLevelImport/AppImportwithDS_Spec.ts new file mode 100644 index 0000000000..c7e3a6c4fc --- /dev/null +++ b/app/client/cypress/e2e/Regression/ServerSide/AppLevelImport/AppImportwithDS_Spec.ts @@ -0,0 +1,37 @@ +import { + agHelper, + appSettings, + homePage, + dataSources, + jsEditor, + deployMode, + locators, + draggableWidgets, +} from "../../../../support/Objects/ObjectsCore"; + +describe("App level import with Datasource", () => { + before(() => { + homePage.CreateNewWorkspace("AppLevelImport", true); + homePage.CreateAppInWorkspace("AppLevelImport"); + }); + + //this tests coveres Applevel import for MySql, Gsheet is covered in Gsheet folder + it("1. Bug #26024 - Import an app at App Level with Datasource - MySql", () => { + appSettings.OpenAppSettings(); + appSettings.GoToImport(); + agHelper.ClickButton("Import"); + homePage.ImportApp("ImportApps/JSOnLoadImport.json", "JSOnLoadTest", true); + cy.wait("@importNewApplication").then(() => { + agHelper.Sleep(); + dataSources.ReconnectSingleDSNAssert("MySQL-Ds", "MySQL"); + }); + jsEditor.ConfirmationClick("Yes"); + agHelper.ClickButton("Got it"); + deployMode.DeployApp(); + jsEditor.ConfirmationClick("Yes"); + agHelper.AssertElementLength( + locators._widgetInDeployed(draggableWidgets.IMAGE), + 10, + ); + }); +}); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Datasources/ConnectionErrors_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Datasources/ConnectionErrors_Spec.ts index 6f1874f6a4..9626160ff0 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Datasources/ConnectionErrors_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Datasources/ConnectionErrors_Spec.ts @@ -29,7 +29,7 @@ describe("Validate Empty DS error messages", () => { agHelper.ValidateToastMessage("Missing database name."); agHelper.WaitUntilAllToastsDisappear(); agHelper.UpdateInputValue( - dataSources._host, + dataSources._host(), dataManager.dsValues[dataManager.defaultEnviorment].postgres_host, ); agHelper.UpdateInputValue( @@ -45,9 +45,7 @@ describe("Validate Empty DS error messages", () => { agHelper.ValidateToastMessage( "An exception occurred while creating connection pool. One or more arguments in the datasource configuration may be invalid.", ); - agHelper.ValidateToastMessage( - "Failed to initialize pool: The server requested password-based authentication, but no password was provided by plugin null", - ); + agHelper.ValidateToastMessage("Failed to initialize pool:"); agHelper.GetNClick(locators._visibleTextSpan("Read only")); propPane.AssertPropertiesDropDownValues("SSL mode", [ "Default", @@ -87,7 +85,7 @@ describe("Validate Empty DS error messages", () => { agHelper.ValidateToastMessage("Missing database name."); agHelper.WaitUntilAllToastsDisappear(); agHelper.UpdateInputValue( - dataSources._host, + dataSources._host(), dataManager.dsValues[dataManager.defaultEnviorment].mysql_host, ); agHelper.UpdateInputValue( @@ -169,7 +167,7 @@ describe("Validate Empty DS error messages", () => { dataSources.TestDatasource(false); agHelper.ValidateToastMessage("Missing endpoint(s)"); agHelper.UpdateInputValue( - dataSources._host, + dataSources._host(), dataManager.dsValues[dataManager.defaultEnviorment].mongo_host, ); agHelper.UpdateInputValue( diff --git a/app/client/cypress/e2e/Regression/ServerSide/Datasources/ElasticSearch_Basic_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Datasources/ElasticSearch_Basic_Spec.ts index 864ca6b694..1572ef281a 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Datasources/ElasticSearch_Basic_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Datasources/ElasticSearch_Basic_Spec.ts @@ -8,10 +8,10 @@ import { describe("Validate Elasticsearch DS", () => { let dsName: any, books: any, - containerName = "elasticsearch1"; + containerName = "elasticsearch"; before("Create a new ElasticSearch DS", () => { - dataSources.StartContainerNVerify("Elasticsearch", containerName, 45000); + //dataSources.StartContainerNVerify("Elasticsearch", containerName, 45000); Since its run in Hosted runs & container is already running, commenting this line dataSources.CreateDataSource("Elasticsearch"); cy.get("@dsName").then(($dsName) => { dsName = $dsName; @@ -79,18 +79,20 @@ describe("Validate Elasticsearch DS", () => { inputFieldName: "Path", }); - //Not able to use below since, we need to enter new line at end - // agHelper.EnterValue(bulkBooks, { - // propFieldName: "", - // directInput: false, - // inputFieldName: "Body", - // }); + //We need to enter new line at end, since without that body data not getting considered + agHelper.EnterValue(bulkBooks, { + propFieldName: "", + directInput: false, + inputFieldName: "Body", + }); - agHelper.TypeIntoTextArea(dataSources._bodyCodeMirror, bulkBooks); + agHelper + .GetElement(dataSources._bodyCodeMirror) + .type("{downarrow}".repeat(10)); agHelper.PressEnter(); - agHelper.Sleep(); + agHelper.Sleep(2000); dataSources.RunQuery(); cy.get("@postExecute").then((resObj: any) => { expect( @@ -123,7 +125,7 @@ describe("Validate Elasticsearch DS", () => { books = JSON.parse( JSON.stringify(resObj.response.body.data.body.hits.total.value), ); - expect(books).to.eq(3); + expect(books).to.be.oneOf([1, 3]); }); //PUT - update @@ -141,6 +143,13 @@ describe("Validate Elasticsearch DS", () => { directInput: false, inputFieldName: "Body", }); + + agHelper + .GetElement(dataSources._bodyCodeMirror) + .type("{downarrow}".repeat(5)); + + agHelper.PressEnter(); + agHelper.Sleep(2000); dataSources.RunQuery(); cy.get("@postExecute").then((resObj: any) => { @@ -205,6 +214,6 @@ describe("Validate Elasticsearch DS", () => { action: "Delete", entityType: entityItems.Datasource, }); - dataSources.StopNDeleteContainer(containerName); + //dataSources.StopNDeleteContainer(containerName); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Datasources/Firestore_Basic_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Firestore_Basic_Spec.ts index 299dec07a3..c05bc0065b 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Datasources/Firestore_Basic_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Firestore_Basic_Spec.ts @@ -3,22 +3,58 @@ import { entityExplorer, dataSources, entityItems, + deployMode, + locators, + draggableWidgets, + table, } from "../../../../support/Objects/ObjectsCore"; +import { Widgets } from "../../../../support/Pages/DataSources"; let dsName: any, + guid: any, cities: any, newCityPath: any, createCity: any, cityName = "LA_"; describe("Validate Firestore DS", () => { - before("Create a new Firestore DS", () => { - dataSources.CreateDataSource("Firestore"); - cy.get("@dsName").then(($dsName) => { - dsName = $dsName; + before("Generate GUID for new Firestore DS", () => { + agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + guid = uid; + dsName = "Firestore" + " " + uid; }); }); - it("1. Validate List/Create/Update/Get", () => { + it("1. Firestore placeholder & mandatory mark verification", () => { + dataSources.NavigateToDSCreateNew(); + dataSources.CreatePlugIn("Firestore"); + agHelper.AssertElementVisibility(dataSources._imgFireStoreLogo); + agHelper.GetNAssertContains(locators._dsName, "Untitled datasource"); + agHelper.GetNClick(locators._dsName); + agHelper.ClearTextField(locators._dsNameTxt); //removing ds name + agHelper.AssertTooltip("Please enter a valid name"); + //agHelper.ValidateToastMessage("Invalid name"); + agHelper.TypeText(locators._dsNameTxt, dsName); + agHelper.PressEnter(); + agHelper.AssertAttribute( + locators._inputFieldByName("Database URL") + "//" + locators._inputField, + "placeholder", + "https://your-project-id.firebaseio.com", + ); + agHelper + .GetElement( + locators._inputFieldByName("Project Id") + "//" + locators._inputField, + ) + .should("not.have.attr", "placeholder"); + dataSources.TestDatasource(false); + agHelper.ValidateToastMessage("Missing Firestore URL."); + agHelper.ValidateToastMessage("Missing ProjectID in datasource."); + agHelper.ValidateToastMessage("Missing ClientJSON in datasource."); + dataSources.FillFirestoreDSForm(); + dataSources.TestSaveDatasource(); + }); + + it("2. Validate List/Create/Update/Get", () => { agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { cityName += uid; @@ -187,11 +223,31 @@ describe("Validate Firestore DS", () => { }); }); - it("2. Validate Upsert [Update & Insert]/Delete documents", () => { - //Validating Upsert + it("3. Validate Widget binding & Deploy app", () => { dataSources.ValidateNSelectDropdown( "Commands", "Get Document", + "List Documents", + ); + agHelper.EnterValue("cities", { + propFieldName: "", + directInput: false, + inputFieldName: "Collection Name", + }); + agHelper.GetNClick(dataSources._whereDelete(0)); //removign where clause, add new condition + dataSources.RunQuery(); + dataSources.AddSuggestedWidget(Widgets.Table); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 0, "v2"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Query1", "Queries/JS"); + }); + + it("4. Validate Upsert [Update & Insert]/Delete documents", () => { + //Validating Upsert + dataSources.ValidateNSelectDropdown( + "Commands", + "List Documents", "Upsert Document", ); @@ -297,11 +353,16 @@ describe("Validate Firestore DS", () => { action: "Delete", entityType: entityItems.Query, }); - entityExplorer.SelectEntityByName(dsName, "Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Delete", - entityType: entityItems.Datasource, - }); + dataSources.DeleteDatasouceFromActiveTab(dsName, 409); + //commenting below since after query delete, we run into risk of not seeing the datasource in EntityExplorer + // entityExplorer.SelectEntityByName(dsName, "Datasources"); + // entityExplorer.ActionContextMenuByEntityName({ + // entityNameinLeftSidebar: dsName, + // action: "Delete", + // entityType: entityItems.Datasource, + // }); + deployMode.DeployApp(); + deployMode.NavigateBacktoEditor(); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts new file mode 100644 index 0000000000..ae79c8e4f0 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts @@ -0,0 +1,466 @@ +import { + agHelper, + dataSources, + propPane, + dataManager, + locators, + entityExplorer, + deployMode, + draggableWidgets, + table, + entityItems, + apiPage, + jsEditor, +} from "../../../../support/Objects/ObjectsCore"; +import { Widgets } from "../../../../support/Pages/DataSources"; + +describe("Validate Oracle DS", () => { + let dataSourceName: string, guid: any, query: string, selectQuery: string; + + before("Generate GUID", () => { + agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + guid = uid; + dataSourceName = "Oracle" + " " + uid; + }); + }); + + it("1. Tc #2354, #2204 - Oracle placeholder & mandatory mark verification", () => { + dataSources.NavigateToDSCreateNew(); + dataSources.CreatePlugIn("Oracle"); + agHelper.GetNAssertContains(locators._dsName, "Untitled datasource"); + agHelper.GetNClick(locators._dsName); + agHelper.ClearTextField(locators._dsNameTxt); //removing ds name + agHelper.AssertTooltip("Please enter a valid name"); + //agHelper.ValidateToastMessage("Invalid name"); + agHelper.TypeText(locators._dsNameTxt, dataSourceName); + agHelper.PressEnter(); + agHelper.AssertAttribute( + dataSources._host(), + "placeholder", + "myapp.abcde.oracle.net", + ); + agHelper.AssertAttribute( + dataSources._databaseName, + "placeholder", + "gfb284db6bcee33_testdb_high.adb.oraclecloud.com", + ); + agHelper.AssertAttribute(dataSources._username, "placeholder", "admin"); + agHelper.AssertAttribute(dataSources._password, "placeholder", "password"); + agHelper.AssertElementLength(dataSources._mandatoryMark, 4); //verifyng all 4 fields are mandatory + agHelper.AssertText(dataSources._host(), "val", ""); + agHelper.UpdateInputValue( + dataSources._host(), + dataManager.dsValues[dataManager.environments[1]].oracle_host, + ); + agHelper.AssertText( + dataSources._host(), + "val", + dataManager.dsValues[dataManager.environments[1]].oracle_host, + ); + agHelper.GetNClick(dataSources._deleteDSHostPort); //Delete the value & verify + agHelper.AssertText(dataSources._host(), "val", ""); + agHelper.ClickButton("Add more"); + agHelper.AssertElementVisibility(dataSources._host("1")); + agHelper.ClickButton("Add more"); + agHelper.AssertElementVisibility(dataSources._host("2")); + Cypress._.times(2, () => { + //Delete the added extra hosts + agHelper.GetNClick(dataSources._deleteDSHostPort); + }); + }); + + it("2. Tc #2357, #2356, #2355, #2354 Verify Oracle connection errors", () => { + dataSources.TestDatasource(false); + agHelper.ValidateToastMessage("Missing endpoint"); + agHelper.ValidateToastMessage("Missing authentication details"); + agHelper.WaitUntilAllToastsDisappear(); + + agHelper.UpdateInputValue( + dataSources._host(), + dataManager.dsValues[dataManager.defaultEnviorment].oracle_host, + ); + agHelper.UpdateInputValue( + dataSources._databaseName, + dataManager.dsValues[dataManager.defaultEnviorment].oracle_service, + ); + dataSources.TestDatasource(false); + agHelper.ValidateToastMessage("Missing username for authentication"); + agHelper.ValidateToastMessage("Missing password for authentication"); + + agHelper.UpdateInputValue( + dataSources._username, + dataManager.dsValues[dataManager.defaultEnviorment].oracle_username, + ); + agHelper.UpdateInputValue( + dataSources._password, + dataManager.dsValues[dataManager.defaultEnviorment].oracle_password, + ); + dataSources.TestDatasource(false); + agHelper.ValidateToastMessage( + "An exception occurred while creating connection pool. One or more arguments in the datasource configuration may be invalid.", + ); + agHelper.ValidateToastMessage("Failed to initialize pool:"); + propPane.AssertPropertiesDropDownValues("SSL mode", ["Disable", "TLS"]); + dataSources.ValidateNSelectDropdown("SSL mode", "TLS", "Disable"); + dataSources.TestSaveDatasource(); + //Validate Review page + dataSources.AssertDataSourceInfo(["Host address", "Port", "Service Name"]); + agHelper.ClickButton("Edit"); //Navigate to Edit page & check if DS edit is opened + dataSources.ValidateNSelectDropdown("SSL mode", "Disable"); + agHelper.GoBack(); //Do not edit anythin, go back to active ds list, ensure no modal is opened + dataSources.AssertDSInActiveList(dataSourceName); + }); + + it("3. Tc #2359, Tc # 2360 , Tc # 2358, Tc # 2366 - Create Insert, Alter & Select queries, Widgets to query binding", () => { + const currentDate = new Date().toISOString().slice(0, 10); + + entityExplorer.DragDropWidgetNVerify(draggableWidgets.DATEPICKER, 200, 50); + propPane.SelectPropertiesDropDown("Date format", "YYYY-MM-DD"); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 500, 50); + propPane.EnterJSContext( + "Source Data", + `[{ + "name": "Cargo Plane", + "value": "Cargo Plane" + }, + { + "name": "Passenger Plane", + "code": "Passenger Plane" + }, + { + "name": "Helicopter", + "code": "Helicopter" + }]`, + ); + propPane.UpdatePropertyFieldValue("Default selected value", "Cargo Plane"); + propPane.AssertPropertiesDropDownValues("Label key", [ + "name", + "code", + "value", + ]); + propPane.SelectPropertiesDropDown( + "Label key", + "value", + "Action", + 0, + 0, + true, + ); + propPane.SelectPropertiesDropDown( + "Value key", + "name", + "Action", + 0, + 1, + true, + ); + dataSources.NavigateFromActiveDS(dataSourceName, true); + query = `CREATE TABLE ${guid} ( + aircraft_id NUMBER(5) PRIMARY KEY, + aircraft_type VARCHAR2(50) NOT NULL, + registration_number VARCHAR2(20) UNIQUE, + manufacturer VARCHAR2(50), + seating_capacity NUMBER(3), + maximum_speed NUMBER(5, 2), + range NUMBER(7, 2), + purchase_date DATE, + maintenance_last_date DATE, + notes CLOB + );`; + agHelper.RenameWithInPane("CreateAircraft"); + dataSources.EnterQuery(query); + dataSources.RunQuery(); + + dataSources.AssertTableInVirtuosoList(dataSourceName, guid.toUpperCase()); + + query = `INSERT INTO ${guid} ( + aircraft_id, + aircraft_type, + registration_number, + manufacturer, + seating_capacity, + maximum_speed, + range, + purchase_date, + maintenance_last_date, + notes) VALUES ( + 1, + '{{Select1.selectedOptionLabel}}', + 'N12345', + 'Boeing', + 150, + 550.03, + 3500.30, + TO_DATE('2020-01-15', 'YYYY-MM-DD'), + TO_DATE('{{DatePicker1.formattedDate}}', 'YYYY-MM-DD'), + 'This aircraft is used for domestic flights.')`; + entityExplorer.ActionTemplateMenuByEntityName(guid.toUpperCase(), "Select"); + dataSources.RunQuery(); + agHelper + .GetText(dataSources._noRecordFound) + .then(($noRecMsg) => expect($noRecMsg).to.eq("No data records to show")); + dataSources.EnterQuery(query); + agHelper.VerifyEvaluatedValue( + `INSERT INTO ${guid} (\n aircraft_id,\n aircraft_type,\n registration_number,\n manufacturer,\n seating_capacity,\n maximum_speed,\n range,\n purchase_date,\n maintenance_last_date,\n notes) VALUES (\n 1,\n $1,\n 'N12345',\n 'Boeing',\n 150,\n 550.03,\n 3500.30,\n TO_DATE('2020-01-15', 'YYYY-MM-DD'),\n TO_DATE($2, 'YYYY-MM-DD'),\n 'This aircraft is used for domestic flights.')`, + ); + dataSources.ToggleUsePreparedStatement(false); + agHelper.GetNClick(locators._codeEditorTarget); + agHelper.VerifyEvaluatedValue( + `INSERT INTO ${guid} (\n aircraft_id,\n aircraft_type,\n registration_number,\n manufacturer,\n seating_capacity,\n maximum_speed,\n range,\n purchase_date,\n maintenance_last_date,\n notes) VALUES (\n 1,\n 'Cargo Plane',\n 'N12345',\n 'Boeing',\n 150,\n 550.03,\n 3500.30,\n TO_DATE('2020-01-15', 'YYYY-MM-DD'),\n TO_DATE('${currentDate}', 'YYYY-MM-DD'),\n 'This aircraft is used for domestic flights.')`, + ); + dataSources.RunQuery(); + selectQuery = `SELECT * FROM ${guid} WHERE ROWNUM < 10`; + dataSources.EnterQuery(selectQuery); + dataSources.RunQueryNVerifyResponseViews(); + dataSources.ToggleUsePreparedStatement(true); + query = `ALTER TABLE ${guid} ADD (raw_data RAW(16), maintenance_interval INTERVAL YEAR(3) TO MONTH);`; + dataSources.EnterQuery(query); + dataSources.RunQuery(); + query = `INSERT INTO ${guid} ( + aircraft_id, + aircraft_type, + registration_number, + manufacturer, + seating_capacity, + maximum_speed, + range, + purchase_date, + maintenance_last_date, + notes, + raw_data, + maintenance_interval) VALUES ( + 4, + 'Passenger Plane', + 'N77777', + 'Airbus', + 100, + 600.67, + 3800.82, + TO_DATE('2017-05-25', 'YYYY-MM-DD'), + TO_DATE('2023-02-18', 'YYYY-MM-DD'), + 'This aircraft is part of the international fleet.', + UTL_RAW.CAST_TO_RAW('raw_value'), + INTERVAL '1' YEAR(3) -- 1 year maintenance interval +);`; + dataSources.EnterQuery(query); + dataSources.RunQuery(); + dataSources.EnterQuery(selectQuery); + dataSources.RunQueryNVerifyResponseViews(2); + query = `INSERT ALL + INTO ${guid} ( + aircraft_id, + aircraft_type, + registration_number, + manufacturer, + seating_capacity, + maximum_speed, + range, + purchase_date, + maintenance_last_date, + notes, + raw_data, + maintenance_interval + ) + VALUES ( + 5, + 'Cargo Plane', + 'N45678', + 'Boeing', + 280, + 570.00, + 5500.00, + TO_DATE('2018-08-30', 'YYYY-MM-DD'), + TO_DATE('2022-12-12', 'YYYY-MM-DD'), + 'This cargo aircraft is used for long-haul freight.', + UTL_RAW.CAST_TO_RAW('cargo_raw_data'), + INTERVAL '2' YEAR(3) -- Two-year maintenance interval + ) + INTO ${guid} ( + aircraft_id, + aircraft_type, + registration_number, + manufacturer, + seating_capacity, + maximum_speed, + range, + purchase_date, + maintenance_last_date, + notes, + raw_data, + maintenance_interval + ) + VALUES ( + 6, + 'Helicopter', + 'N98765', + 'Robinson', + 2, + 150.00, + 350.00, + TO_DATE('2019-06-15', 'YYYY-MM-DD'), + TO_DATE('2023-08-20', 'YYYY-MM-DD'), + 'This helicopter is used for aerial photography.', + UTL_RAW.CAST_TO_RAW('helicopter_raw'), + INTERVAL '6' MONTH -- Six-month maintenance interval + ); + SELECT * FROM DUAL;`; + dataSources.EnterQuery(query); + dataSources.RunQuery(); + dataSources.EnterQuery(selectQuery); + dataSources.RunQueryNVerifyResponseViews(4); + selectQuery = selectQuery + ` and aircraft_id IN (1, 6)`; + dataSources.EnterQuery(selectQuery); + dataSources.RunQueryNVerifyResponseViews(2); + dataSources.AddSuggestedWidget(Widgets.Table); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 0, "v2"); + table.ReadTableRowColumnData(0, 10, "v2").then(($cellData) => { + expect($cellData).to.be.empty; + }); + table.ReadTableRowColumnData(0, 11, "v2").then(($cellData) => { + expect($cellData).to.be.empty; + }); + table.ReadTableRowColumnData(1, 10, "v2").then(($cellData) => { + expect($cellData).not.to.be.empty; + }); + table.ReadTableRowColumnData(1, 11, "v2").then(($cellData) => { + expect($cellData).not.to.be.empty; + }); + deployMode.NavigateBacktoEditor(); + }); + + it("4. Tc #2362 - Update query validation", () => { + entityExplorer.SelectEntityByName("Query1", "Queries/JS"); + query = `UPDATE ${guid} +SET + maximum_speed = CASE + WHEN seating_capacity <= 100 THEN 400.89 + WHEN seating_capacity > 100 AND seating_capacity <= 200 THEN 500.96 + ELSE 600.00 + END, + maintenance_interval = CASE + WHEN seating_capacity <= 50 THEN INTERVAL '3' MONTH + WHEN seating_capacity > 50 AND seating_capacity <= 150 THEN TO_YMINTERVAL('0-6') + ELSE TO_YMINTERVAL('1-0') + END +WHERE aircraft_type = 'Passenger Plane'`; + dataSources.EnterQuery(query); + dataSources.RunQuery(); + selectQuery = selectQuery + ` or aircraft_type = 'Passenger Plane'`; + dataSources.EnterQuery(selectQuery); + dataSources.RunQueryNVerifyResponseViews(3); + dataSources.AddSuggestedWidget( + Widgets.Table, + dataSources._addSuggestedExisting, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 0, "v2"); + table.ReadTableRowColumnData(1, 5, "v2").then(($cellData) => { + expect($cellData).to.eq("400.89"); + }); + table.ReadTableRowColumnData(1, 11, "v2").then(($cellData) => { + expect($cellData).to.eq("0-6"); + }); + deployMode.NavigateBacktoEditor(); + }); + + it("5. Tc #2361 - Delete query validation", () => { + entityExplorer.SelectEntityByName("Query1", "Queries/JS"); + query = `DELETE FROM ${guid} + WHERE + (aircraft_type = 'Cargo Plane' AND seating_capacity <= 100) + OR + (aircraft_type = 'Passenger Plane' AND purchase_date < TO_DATE('2020-01-01', 'YYYY-MM-DD')) + OR + (aircraft_type = 'Helicopter' AND manufacturer = 'Robinson' AND maintenance_interval = INTERVAL '6' MONTH)`; + dataSources.EnterQuery(query); + dataSources.RunQuery(); + selectQuery = `SELECT * FROM ${guid}`; + dataSources.EnterQuery(selectQuery); + dataSources.RunQueryNVerifyResponseViews(2); + dataSources.AddSuggestedWidget( + Widgets.Table, + dataSources._addSuggestedExisting, + ); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 0, "v2"); + for (let i = 0; i < 2; i++) { + table.ReadTableRowColumnData(i, 1, "v2").then(($cellData) => { + expect($cellData).to.eq("Cargo Plane"); + }); + } + + table.OpenNFilterTable("MAINTENANCE_INTERVAL", "not empty"); + table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { + expect($cellData).to.eq("5"); + }); + agHelper + .GetText(table._showPageItemsCount) + .then(($count) => expect($count).contain("1")); + table.CloseFilter(); + agHelper + .GetText(table._filtersCount) + .then(($count) => expect($count).contain("1")); + deployMode.NavigateBacktoEditor(); + }); + + it("6. Tc #2363 - Copy & Move query validations", () => { + entityExplorer.SelectEntityByName("Query1", "Queries/JS"); + agHelper.ActionContextMenuWithInPane({ + action: "Copy to page", + subAction: "Page1", + toastToValidate: "copied to page", + }); + agHelper.GetNAssertContains(locators._queryName, "Query1Copy"); + dataSources.RunQueryNVerifyResponseViews(2); + entityExplorer.AddNewPage(); + entityExplorer.SelectEntityByName("Page1", "Pages"); + agHelper.ActionContextMenuWithInPane({ + action: "Move to page", + subAction: "Page2", + toastToValidate: "moved to page", + }); + agHelper.WaitUntilAllToastsDisappear(); + agHelper.GetNAssertContains(locators._queryName, "Query1Copy"); + dataSources.RunQueryNVerifyResponseViews(2); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.Query, + }); + entityExplorer.SelectEntityByName("Page1", "Pages"); + entityExplorer.SelectEntityByName("Query1", "Queries/JS"); + }); + + it("7. Tc #2365 - Query settings tab validations", () => { + apiPage.ToggleOnPageLoadRun(false); // ALl above cases validated for onpage load run with confirmation dialog set to false + apiPage.ToggleConfirmBeforeRunning(true); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitForTableEmpty("v2"); + deployMode.NavigateBacktoEditor(); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 300, 500); + propPane.EnterJSContext("onClick", `{{Query1.run()}}`); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + agHelper.ClickButton("Submit"); + jsEditor.ConfirmationClick("No"); //Handling both No & Yes from confirmation dialog + agHelper.AssertContains("cancelled"); + agHelper.WaitUntilAllToastsDisappear(); + agHelper.ClickButton("Submit"); + jsEditor.ConfirmationClick("Yes"); + table.WaitUntilTableLoad(0, 0, "v2"); + deployMode.NavigateBacktoEditor(); + }); + + after( + "Verify Deletion of the Oracle datasource after all created queries are deleted", + () => { + dataSources.DeleteDatasourceFromWithinDS(dataSourceName, 409); //Since all queries exists + entityExplorer.ExpandCollapseEntity("Queries/JS"); + entityExplorer.DeleteAllQueriesForDB(dataSourceName); + deployMode.DeployApp(); + deployMode.NavigateBacktoEditor(); + entityExplorer.ExpandCollapseEntity("Queries/JS"); + dataSources.DeleteDatasourceFromWithinDS(dataSourceName, 200); + }, + ); +}); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Datasources/Redis_Basic_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Redis_Basic_Spec.ts index 1e28e637df..ef15f2d9a8 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Datasources/Redis_Basic_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Redis_Basic_Spec.ts @@ -1,6 +1,5 @@ import { agHelper, - entityExplorer, dataSources, entityItems, } from "../../../../support/Objects/ObjectsCore"; @@ -98,11 +97,13 @@ describe("Validate Redis DS", () => { action: "Delete", entityType: entityItems.Query, }); - entityExplorer.SelectEntityByName(dsName, "Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Delete", - entityType: entityItems.Datasource, - }); + dataSources.DeleteDatasouceFromActiveTab(dsName); + //commenting below since after query delete, we run into risk of not seeing the datasource in EntityExplorer + // entityExplorer.SelectEntityByName(dsName, "Datasources"); + // entityExplorer.ActionContextMenuByEntityName({ + // entityNameinLeftSidebar: dsName, + // action: "Delete", + // entityType: entityItems.Datasource, + // }); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MongoURI_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MongoURI_Spec.ts index d0d37bb8f9..f79b8aa170 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MongoURI_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MongoURI_Spec.ts @@ -204,7 +204,7 @@ function GenerateCRUDNValidateDeployPage( agHelper.AssertContains("Successfully generated a page"); // Commenting this since FindQuery failure appears sometimes assertHelper.AssertNetworkStatus("@getActions", 200); assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); appSettings.OpenPaneAndChangeTheme("Pacific"); deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts index 6b3ecb4a50..ebcadedae6 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts @@ -96,7 +96,7 @@ describe("Validate Mongo CRUD with JSON Form", () => { agHelper.AssertContains("Successfully generated a page"); // Commenting this since FindQuery failure appears sometimes assertHelper.AssertNetworkStatus("@getActions", 200); assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts index 4bcc58c079..104c233c10 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL1_Spec.ts @@ -158,15 +158,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { entityType: entityItems.Query, }); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("productlines"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "productlines"); }); it("5. Verify Generate CRUD for the new table & Verify Deploy mode for table - Productlines", () => { @@ -178,7 +170,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201); assertHelper.AssertNetworkStatus("@getActions", 200); assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); @@ -218,42 +210,43 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { _.dataSources.AssertJSONFormHeader(0, 0, "productLine"); }); - it.skip("6. Verify Update/Delete row/Delete field data from Deploy page - on Productlines - existing record + Bug 14063", () => { - entityExplorer.SelectEntityByName("update_form", "Widgets"); - propPane.ChangeJsonFormFieldType( - "Text Description", - "Multiline Text Input", - ); - _.propPane.NavigateBackToPropertyPane(); - _.propPane.ChangeJsonFormFieldType( - "Html Description", - "Multiline Text Input", - ); - propPane.NavigateBackToPropertyPane(); - deployMode.DeployApp(); - table.SelectTableRow(0, 0, false); //to make JSON form hidden - agHelper.AssertElementAbsence(locators._jsonFormWidget); - table.SelectTableRow(3); - agHelper.AssertElementVisibility(locators._jsonFormWidget); + //Open Bug 14063 - hence skipping + // it.skip("6. Verify Update/Delete row/Delete field data from Deploy page - on Productlines - existing record + Bug 14063", () => { + // entityExplorer.SelectEntityByName("update_form", "Widgets"); + // propPane.ChangeJsonFormFieldType( + // "Text Description", + // "Multiline Text Input", + // ); + // propPane.NavigateBackToPropertyPane(); + // propPane.ChangeJsonFormFieldType( + // "Html Description", + // "Multiline Text Input", + // ); + // propPane.NavigateBackToPropertyPane(); + // deployMode.DeployApp(); + // table.SelectTableRow(0, 0, false); //to make JSON form hidden + // agHelper.AssertElementAbsence(locators._jsonFormWidget); + // table.SelectTableRow(3); + // agHelper.AssertElementVisibility(locators._jsonFormWidget); - _.dataSources.AssertJSONFormHeader(3, 0, "productLine"); + // dataSources.AssertJSONFormHeader(3, 0, "productLine"); - _.deployMode.EnterJSONTextAreaValue( - "Html Description", - "The largest cruise ship is twice the length of the Washington Monument. Some cruise ships have virtual balconies.", - ); - agHelper.ClickButton("Update"); //Update does not work, Bug 14063 - agHelper.AssertElementAbsence(locators._toastMsg); //Validating fix for Bug 14063 - assertHelper.AssertNetworkStatus("@postExecute", 200); - table.AssertSelectedRow(3); + // deployMode.EnterJSONTextAreaValue( + // "Html Description", + // "The largest cruise ship is twice the length of the Washington Monument. Some cruise ships have virtual balconies.", + // ); + // agHelper.ClickButton("Update"); //Update does not work, Bug 14063 + // agHelper.AssertElementAbsence(locators._toastMsg); //Validating fix for Bug 14063 + // assertHelper.AssertNetworkStatus("@postExecute", 200); + // table.AssertSelectedRow(3); - //validating update happened fine! - _.table.ReadTableRowColumnData(3, 2, "v1", 200).then(($cellData) => { - expect($cellData).to.eq( - "The largest cruise ship is twice the length of the Washington Monument. Some cruise ships have virtual balconies.", - ); - }); - }); + // //validating update happened fine! + // table.ReadTableRowColumnData(3, 2, "v1", 200).then(($cellData) => { + // expect($cellData).to.eq( + // "The largest cruise ship is twice the length of the Washington Monument. Some cruise ships have virtual balconies.", + // ); + // }); + // }); // it.skip("7. Verify Add/Update/Delete from Deploy page - on Productlines - new record + Bug 14063", () => { // //To script aft bug fix! @@ -308,7 +301,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { after( "Verify Deletion of the datasource when Pages/Actions associated are not removed yet", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Customers page & queries still active + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Customers page & queries still active }, ); @@ -323,7 +316,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { agHelper.AssertContains("Successfully generated a page"); //assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); table.WaitUntilTableLoad(); diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts index e51ba0d214..12e1f4b523 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts @@ -21,14 +21,14 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { // } else cy.log("MySQL DB is found, hence using actual DB"); // }); - it("1. Create DS for generating CRUD template", () => { + before("1. Create DS for generating CRUD template", () => { dataSources.CreateDataSource("MySql"); cy.get("@dsName").then(($dsName) => { dsName = $dsName; }); }); - it("2. Create new CRUD Table 'Stores' and populate & refresh Entity Explorer to find the new table", () => { + it("1. Create new CRUD Table 'Stores' and populate & refresh Entity Explorer to find the new table", () => { let tableCreateQuery = `CREATE TABLE Stores( store_id INTEGER NOT NULL PRIMARY KEY ,name VARCHAR(36) NOT NULL @@ -69,19 +69,13 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { entityType: entityItems.Query, }); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("Stores"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "Stores"); }); - it("3. Validate Select record from Postgress datasource & verify query response", () => { - entityExplorer.ActionTemplateMenuByEntityName("Stores", "SELECT"); + it("2. Validate Select record from Postgress datasource & verify query response", () => { + //entityExplorer.ActionTemplateMenuByEntityName("Stores", "Select"); + dataSources.NavigateFromActiveDS(dsName, true); + dataSources.EnterQuery("SELECT * FROM Stores LIMIT 10"); dataSources.RunQueryNVerifyResponseViews(10); dataSources.AssertQueryTableResponse(5, "2112"); dataSources.AssertQueryTableResponse(6, "Mike's Liquors"); @@ -91,7 +85,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { }); }); - it("4. Verify Generate CRUD for the new table & Verify Deploy mode for table - Stores", () => { + it("3. Verify Generate CRUD for the new table & Verify Deploy mode for table - Stores", () => { dataSources.NavigateFromActiveDS(dsName, false); agHelper.GetNClick(dataSources._selectTableDropdown, 0, true); agHelper.GetNClickByContains(dataSources._dropdownOption, "Stores"); @@ -106,7 +100,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { table.WaitUntilTableLoad(); }); - it("5. Verify Update data from Deploy page - on Stores - existing record", () => { + it("4. Verify Update data from Deploy page - on Stores - existing record", () => { entityExplorer.SelectEntityByName("update_form", "Widgets"); updatingStoreJSONPropertyFileds(); @@ -144,7 +138,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { //Hidden field bug - to add here aft secret codes are updated for some fields! }); - it("6. Verify Delete field data from Deploy page - on Stores - existing record", () => { + it("5. Verify Delete field data from Deploy page - on Stores - existing record", () => { table.SelectTableRow(4); //Deleting field value from UI - since MYSQL - "" also considered a value & hence even though this field is NOT NULL - no validations dataSources.AssertJSONFormHeader(4, 0, "store_id"); @@ -161,7 +155,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { updateNVerify(8, 3, ""); }); - it("7. Verify Delete row from Deploy page - on Stores - existing record", () => { + it("6. Verify Delete row from Deploy page - on Stores - existing record", () => { table.SelectTableRow(5); dataSources.AssertJSONFormHeader(5, 0, "store_id"); agHelper.ClickButton("Delete", 5); @@ -188,7 +182,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { dataSources.AssertJSONFormHeader(0, 0, "store_id"); }); - it("8. Verify Refresh table from Deploy page - on Stores & verify all updates persists", () => { + it("7. Verify Refresh table from Deploy page - on Stores & verify all updates persists", () => { agHelper.GetNClick(dataSources._refreshIcon); //Store Address deletion remains @@ -220,7 +214,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { table.WaitUntilTableLoad(); }); - it("9. Verify Add/Insert from Deploy page - on Stores - new record", () => { + it("8. Verify Add/Insert from Deploy page - on Stores - new record", () => { deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(); entityExplorer.ExpandCollapseEntity("Widgets"); @@ -280,7 +274,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { .then(($len) => expect($len).to.eq(1)); }); - it("10. Verify Update fields/Delete from Deploy page - on Stores - newly inserted record", () => { + it("9. Verify Update fields/Delete from Deploy page - on Stores - newly inserted record", () => { table.SelectTableRow(0); //validating update happened fine! @@ -338,7 +332,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { }); }); - it("11. Validate Deletion of the Newly Created Page - Stores", () => { + it("10. Validate Deletion of the Newly Created Page - Stores", () => { deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(); //Delete the test data @@ -350,7 +344,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { agHelper.RefreshPage(); }); - it("12. Validate Drop of the Newly Created - Stores - Table from MySQL datasource", () => { + it("11. Validate Drop of the Newly Created - Stores - Table from MySQL datasource", () => { let deleteTblQuery = "DROP TABLE Stores;"; dataSources.NavigateFromActiveDS(dsName, true); agHelper.RenameWithInPane("DropStores"); @@ -374,11 +368,14 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { ); }); - it("13. Verify Deletion of the datasource when Pages/Actions associated are not removed yet", () => { - deployMode.DeployApp(); - deployMode.NavigateBacktoEditor(); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); - }); + after( + "Verify Deletion of the datasource when Pages/Actions associated are not removed yet", + () => { + deployMode.DeployApp(); + deployMode.NavigateBacktoEditor(); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); + }, + ); function GenerateCRUDNValidateDeployPage( col1Text: string, @@ -391,7 +388,7 @@ describe("Validate MySQL Generate CRUD with JSON Form", () => { agHelper.AssertContains("Successfully generated a page"); //assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); table.WaitUntilTableLoad(); diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts index 220be95da0..b0dab2fac1 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres1_Spec.ts @@ -116,7 +116,7 @@ describe("Postgres Generate CRUD with JSON Form", () => { it("4. Verify Deletion of the datasource when Pages/Actions associated are not removed yet", () => { deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Suppliers Page - 1 still using this ds + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Suppliers Page - 1 still using this ds }); function GenerateCRUDNValidateDeployPage( @@ -130,7 +130,7 @@ describe("Postgres Generate CRUD with JSON Form", () => { agHelper.AssertContains("Successfully generated a page"); //assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres2_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres2_Spec.ts index 03ae095e42..32b811d832 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres2_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Postgres2_Spec.ts @@ -21,33 +21,33 @@ describe("Validate Postgres Generate CRUD with JSON Form", () => { it("1. Create new CRUD Table 'Vessels' and populate & refresh Entity Explorer to find the new table", () => { const tableCreateQuery = `CREATE TABLE Vessels( - SHIP_ID INTEGER NOT NULL PRIMARY KEY - ,CALLSIGN VARCHAR(7) - ,SHIPNAME VARCHAR(30) NOT NULL - ,COUNTRY VARCHAR(16) NOT NULL - ,NEXT_PORT_NAME VARCHAR(20) - ,DESTINATION VARCHAR(29) - ,VESSEL_TYPE VARCHAR(17) NOT NULL - ,TIMEZONE NUMERIC(4,1) - ,STATUS_NAME VARCHAR(26) NOT NULL - ,YEAR_BUILT INTEGER - ,AREA_CODE VARCHAR(33) NOT NULL - ,SPEED NUMERIC(8,4) - ,ETA_UPDATED VARCHAR(19) - ,DISTANCE_TO_GO INTEGER NOT NULL - ,CURRENT_PORT VARCHAR(20) - ); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (371681,'ZCEF6','QUEEN MARY 2','Bermuda','STAVANGER','STAVANGER,NORWAY','Passenger',2,'Moored',2003,'NORDIC - Norwegian Coast',0.0,NULL,0,'STAVANGER'); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (5630138,'H3RC','EVER GIVEN','Panama','KAOHSIUNG','KAOHSIUNG','Cargo',8,'Underway using Engine',2018,'SCHINA - South China',20.5,'2022-05-27 11:10:00',609,NULL); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (371584,'ZCDX4','ECLIPSE','Bermuda',NULL,'CRUISING','Pleasure Craft',3,'At Anchor',2010,'EMED - East Mediterranean',0.1,NULL,0,NULL); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (371668,'ZCEF2','QUEEN ELIZABETH','Bermuda','MANZANILLO','MANZANILLO','Passenger',-7,'Underway using Engine',2010,'WCCA - West Coast Central America',15.1,'2022-05-27 11:29:00',9,NULL); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (400773,'WDH2111','TIME BANDIT','USA',NULL,'FISHGROUNDS','Fishing',-8,'Underway using Engine',1991,'ALASKA - Alaska',8.0,NULL,0,'HOMER'); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (372813,'C6XS7','OASIS OF THE SEAS','Bahamas','BAYONNE','BAYONNE','Passenger',-5,'Underway using Engine',2009,'CARIBS - Caribbean Sea',19.0,'2022-05-27 04:52:00',3872,NULL); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (435572,'WDC6082','WIZARD','USA','SEATTLE','SEATTLE','Fishing',-7,'Stopped',1945,'USWC - US West Coast',0.0,NULL,0,'SEATTLE'); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (442329,'WDE5199','NORTHWESTERN','USA','SHILSHOLE','SHILSHOLE','Fishing',-7,'Moored',1977,'USWC - US West Coast',0.0,NULL,0,'SEATTLE'); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (429068,'WYR4481','PAUL R TREGURTHA','USA','ST CLAIR','ST CLAIR','Cargo',-4,'Moored',1981,'GLAKES - Great Lakes',0.0,NULL,0,'ST CLAIR'); - INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (159196,'OYGR2','EMMA MAERSK','Denmark','SHANGHAI','CNNBO>CNYSN','Cargo',8,'Underway using Engine',2006,'CCHINA - Central China',8.2,'2022-05-27 10:55:00',143,NULL); - `; + SHIP_ID INTEGER NOT NULL PRIMARY KEY + ,CALLSIGN VARCHAR(7) + ,SHIPNAME VARCHAR(30) NOT NULL + ,COUNTRY VARCHAR(16) NOT NULL + ,NEXT_PORT_NAME VARCHAR(20) + ,DESTINATION VARCHAR(29) + ,VESSEL_TYPE VARCHAR(17) NOT NULL + ,TIMEZONE NUMERIC(4,1) + ,STATUS_NAME VARCHAR(26) NOT NULL + ,YEAR_BUILT INTEGER + ,AREA_CODE VARCHAR(33) NOT NULL + ,SPEED NUMERIC(8,4) + ,ETA_UPDATED VARCHAR(19) + ,DISTANCE_TO_GO INTEGER NOT NULL + ,CURRENT_PORT VARCHAR(20) + ); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (371681,'ZCEF6','QUEEN MARY 2','Bermuda','STAVANGER','STAVANGER,NORWAY','Passenger',2,'Moored',2003,'NORDIC - Norwegian Coast',0.0,NULL,0,'STAVANGER'); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (5630138,'H3RC','EVER GIVEN','Panama','KAOHSIUNG','KAOHSIUNG','Cargo',8,'Underway using Engine',2018,'SCHINA - South China',20.5,'2022-05-27 11:10:00',609,NULL); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (371584,'ZCDX4','ECLIPSE','Bermuda',NULL,'CRUISING','Pleasure Craft',3,'At Anchor',2010,'EMED - East Mediterranean',0.1,NULL,0,NULL); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (371668,'ZCEF2','QUEEN ELIZABETH','Bermuda','MANZANILLO','MANZANILLO','Passenger',-7,'Underway using Engine',2010,'WCCA - West Coast Central America',15.1,'2022-05-27 11:29:00',9,NULL); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (400773,'WDH2111','TIME BANDIT','USA',NULL,'FISHGROUNDS','Fishing',-8,'Underway using Engine',1991,'ALASKA - Alaska',8.0,NULL,0,'HOMER'); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (372813,'C6XS7','OASIS OF THE SEAS','Bahamas','BAYONNE','BAYONNE','Passenger',-5,'Underway using Engine',2009,'CARIBS - Caribbean Sea',19.0,'2022-05-27 04:52:00',3872,NULL); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (435572,'WDC6082','WIZARD','USA','SEATTLE','SEATTLE','Fishing',-7,'Stopped',1945,'USWC - US West Coast',0.0,NULL,0,'SEATTLE'); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (442329,'WDE5199','NORTHWESTERN','USA','SHILSHOLE','SHILSHOLE','Fishing',-7,'Moored',1977,'USWC - US West Coast',0.0,NULL,0,'SEATTLE'); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (429068,'WYR4481','PAUL R TREGURTHA','USA','ST CLAIR','ST CLAIR','Cargo',-4,'Moored',1981,'GLAKES - Great Lakes',0.0,NULL,0,'ST CLAIR'); + INSERT INTO Vessels(SHIP_ID,CALLSIGN,SHIPNAME,COUNTRY,NEXT_PORT_NAME,DESTINATION,VESSEL_TYPE,TIMEZONE,STATUS_NAME,YEAR_BUILT,AREA_CODE,SPEED,ETA_UPDATED,DISTANCE_TO_GO,CURRENT_PORT) VALUES (159196,'OYGR2','EMMA MAERSK','Denmark','SHANGHAI','CNNBO>CNYSN','Cargo',8,'Underway using Engine',2006,'CCHINA - Central China',8.2,'2022-05-27 10:55:00',143,NULL); + `; dataSources.NavigateFromActiveDS(dsName, true); @@ -57,27 +57,19 @@ describe("Validate Postgres Generate CRUD with JSON Form", () => { //agHelper.VerifyEvaluatedValue(tableCreateQuery); //failing sometimes! dataSources.RunQueryNVerifyResponseViews(); + dataSources.AssertTableInVirtuosoList(dsName, "public.vessels"); + }); + + it("2. Validate Select record from Postgress datasource & verify query response", () => { + entityExplorer.ActionTemplateMenuByEntityName("public.vessels", "Select"); + dataSources.RunQueryNVerifyResponseViews(10); + dataSources.AssertQueryTableResponse(0, "371681"); + dataSources.AssertQueryTableResponse(6, "Passenger"); agHelper.ActionContextMenuWithInPane({ action: "Delete", entityType: entityItems.Query, }); - - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.vessels"), - ); - }); - - it("2. Validate Select record from Postgress datasource & verify query response", () => { - entityExplorer.ActionTemplateMenuByEntityName("public.vessels", "SELECT"); - dataSources.RunQueryNVerifyResponseViews(10); - dataSources.AssertQueryTableResponse(0, "371681"); - dataSources.AssertQueryTableResponse(6, "Passenger"); + entityExplorer.SelectEntityByName("CreateVessels"); agHelper.ActionContextMenuWithInPane({ action: "Delete", entityType: entityItems.Query, @@ -93,7 +85,7 @@ describe("Validate Postgres Generate CRUD with JSON Form", () => { assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201); assertHelper.AssertNetworkStatus("@getActions", 200); assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); assertHelper.AssertNetworkStatus("@updateLayout", 200); deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); @@ -620,15 +612,7 @@ describe("Validate Postgres Generate CRUD with JSON Form", () => { agHelper.FocusElement(locators._codeMirrorTextArea); dataSources.RunQueryNVerifyResponseViews(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementAbsence( - entityExplorer._entityNameInExplorer("public.vessels"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.vessels", false); }); it("17. Verify application does not break when user runs the query with wrong table name", function () { @@ -649,7 +633,7 @@ describe("Validate Postgres Generate CRUD with JSON Form", () => { it("18. Verify Deletion of the datasource when Pages/Actions associated are not removed yet", () => { deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }); function generateCallsignInfo(rowIndex: number) { diff --git a/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/Fetch_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/Fetch_Spec.ts index b16b862cbd..7595eda9a8 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/Fetch_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/Fetch_Spec.ts @@ -72,7 +72,7 @@ describe("Tests fetch calls", () => { agHelper.AssertContains("anonymousUser", "exist"); }); - it.skip("3. Tests if fetch works with store value", function () { + it("3. Tests if fetch works with store value", function () { entityExplorer.NavigateToSwitcher("Widgets"); entityExplorer.DragDropWidgetNVerify("buttonwidget", 500, 200); entityExplorer.SelectEntityByName("Button1"); diff --git a/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts index db1de0c85c..2adba0d02d 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts @@ -366,13 +366,13 @@ describe("JS Function Execution", function () { : i === functionsLength - 1 ? ` ${functionName}: ${ - isMarkedAsync ? "async" : "" - } ()=>"${functionName}", + isMarkedAsync ? "async" : "" + } ()=>"${functionName}", }` : ` ${functionName}: ${ - isMarkedAsync ? "async" : "" - } ()=> "${functionName}",`; + isMarkedAsync ? "async" : "" + } ()=> "${functionName}",`; } return JS_OBJECT_BODY; }; @@ -406,7 +406,8 @@ describe("JS Function Execution", function () { //After JSObj is created - check methods are in alphabetical order assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_DEFAULT_DATA); - _.agHelper.RefreshPage(); + agHelper.RefreshPage(); + agHelper.Sleep(2000); //for confirmatiom modal to appear before clicking on "Yes" button for CI runs // click "Yes" button for all onPageload && ConfirmExecute functions for (let i = 0; i <= onPageLoadAndConfirmExecuteFunctionsLength - 1; i++) { //agHelper.AssertElementPresence(jsEditor._dialog("Confirmation Dialog")); // Not working in edit mode @@ -549,22 +550,16 @@ return "yes";`; // Assert that response tab is not empty _.agHelper.AssertContains("No signs of trouble here!", "not.exist"); // Assert presence of typeError in response tab - _.agHelper.AssertContains( - "Cannot read properties of undefined (reading 'id')", - "exist", - ); - _.agHelper.AssertContains("TypeError", "exist"); + agHelper.AssertContains('"Table1.unknown" is undefined', "exist"); + agHelper.AssertContains("TypeError", "exist"); // click the error tab agHelper.GetNClick(locators._errorTab); // Assert that errors tab is not empty _.agHelper.AssertContains("No signs of trouble here!", "not.exist"); // Assert presence of typeError in error tab - _.agHelper.AssertContains( - "Cannot read properties of undefined (reading 'id')", - "exist", - ); - _.agHelper.AssertContains("TypeError", "exist"); + agHelper.AssertContains('"Table1.unknown" is undefined', "exist"); + agHelper.AssertContains("TypeError", "exist"); // Fix parse error and assert that debugger error is removed jsEditor.EditJSObj(JS_OBJECT_WITHOUT_PARSE_ERROR, true, false); @@ -573,10 +568,7 @@ return "yes";`; //agHelper.AssertContains("ran successfully"); //commenting since 'Resource not found' comes sometimes due to fast parsing agHelper.AssertElementAbsence(locators._btnSpinner, 10000); agHelper.GetNClick(locators._errorTab); - agHelper.AssertContains( - "Cannot read properties of undefined (reading 'id')", - "not.exist", - ); + agHelper.AssertContains('"Table1.unknown" is undefined', "not.exist"); // Switch back to response tab agHelper.GetNClick(locators._responseTab); @@ -590,10 +582,7 @@ return "yes";`; _.jsEditor.EditJSObj(JS_OBJECT_WITH_DELETED_FUNCTION, true, false); // Assert that parse error is removed from debugger when function is deleted agHelper.GetNClick(locators._errorTab); - agHelper.AssertContains( - "Cannot read properties of undefined (reading 'id')", - "not.exist", - ); + agHelper.AssertContains('"Table1.unknown" is undefined.', "not.exist"); agHelper.ActionContextMenuWithInPane({ action: "Delete", entityType: entityItems.JSObject, diff --git a/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/Basic_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/Basic_Spec.ts index 3e40f65ac8..51bfcd829e 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/Basic_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/Basic_Spec.ts @@ -31,19 +31,12 @@ describe("MySQL Datatype tests", function () { dataSources.CreateQueryFromOverlay(dsName, query, "createTable"); //Creating query from EE overlay dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer(inputData.tableName), - ); + dataSources.AssertTableInVirtuosoList(dsName, inputData.tableName); //Creating SELECT query entityExplorer.ActionTemplateMenuByEntityName( inputData.tableName, - "SELECT", + "Select", ); agHelper.RenameWithInPane("selectRecords"); dataSources.RunQuery(); @@ -55,7 +48,7 @@ describe("MySQL Datatype tests", function () { query = inputData.query.insertRecord; entityExplorer.ActionTemplateMenuByEntityName( inputData.tableName, - "INSERT", + "Insert", ); agHelper.RenameWithInPane("insertRecord"); dataSources.EnterQuery(query); @@ -63,7 +56,7 @@ describe("MySQL Datatype tests", function () { query = inputData.query.dropTable; entityExplorer.ActionTemplateMenuByEntityName( inputData.tableName, - "DELETE", + "Delete", ); agHelper.RenameWithInPane("dropTable"); dataSources.EnterQuery(query); @@ -83,10 +76,11 @@ describe("MySQL Datatype tests", function () { }); i % 2 && agHelper.ToggleSwitch("Bool_column"); agHelper.ClickButton("insertRecord"); + agHelper.Sleep(2000); //for the modal to close after entering all values & value to reflect in table agHelper.AssertElementVisibility( locators._buttonByText("Run InsertQuery"), ); - agHelper.Sleep(2000); + agHelper.Sleep(3000); }); }); @@ -146,7 +140,7 @@ describe("MySQL Datatype tests", function () { entityExplorer.ExpandCollapseEntity("Datasources", false); //DS deletion - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); ["createTable", "dropTable", "insertRecord", "selectRecords"].forEach( (type) => { @@ -160,7 +154,7 @@ describe("MySQL Datatype tests", function () { deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }, ); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/False_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/False_Spec.ts index ff5cf83f65..455b4729a2 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/False_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/MySQL_Datatypes/False_Spec.ts @@ -19,14 +19,7 @@ describe("MySQL Datatype tests", function () { dataSources.CreateQueryAfterDSSaved(query, "createTable"); //Creating query from EE overlay dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer(inputData.tableName), - ); + dataSources.AssertTableInVirtuosoList(dsName, inputData.tableName); }); }); @@ -34,7 +27,7 @@ describe("MySQL Datatype tests", function () { it("1. False Cases & Long Integer as query param", () => { entityExplorer.ActionTemplateMenuByEntityName( inputData.tableName, - "INSERT", + "Insert", ); agHelper.RenameWithInPane("falseCases"); inputData.falseResult.forEach((res_array, i) => { @@ -78,7 +71,7 @@ describe("MySQL Datatype tests", function () { deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }, ); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad1_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad1_Spec.ts index 8979e3a414..6616af78e8 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad1_Spec.ts @@ -112,7 +112,7 @@ describe("JSObjects OnLoad Actions tests", function () { }); //Skipping due to - "tableData":"ERROR: invalid input syntax for type smallint: "{}"" - it.skip("4. Tc 53 - Verify OnPage Load - Enabled & Disabling - Before Function calling for JSOBject", function () { + it("4. Tc 53 - Verify OnPage Load - Enabled & Disabling - Before Function calling for JSOBject", function () { entityExplorer.SelectEntityByName(jsName as string, "Queries/JS"); jsEditor.EnableDisableAsyncFuncSettings("getEmployee", true, false); //jsEditor.RunJSObj(); //Even running JS functin before delpoying does not help @@ -136,8 +136,8 @@ describe("JSObjects OnLoad Actions tests", function () { jsEditor.EnableDisableAsyncFuncSettings("getEmployee", false, true); deployMode.DeployApp(locators._widgetInDeployed("tablewidget"), false); agHelper.WaitUntilToastDisappear('The action "GetEmployee" has failed'); - deployMode.NavigateBacktoEditor(); - agHelper.WaitUntilToastDisappear('The action "GetEmployee" has failed'); + deployMode.NavigateBacktoEditor('The action "GetEmployee" has failed'); + //agHelper.WaitUntilToastDisappear('The action "GetEmployee" has failed'); // ee.ExpandCollapseEntity("Queries/JS"); // ee.SelectEntityByName(jsName as string); // jsEditor.EnableDisableAsyncFuncSettings("getEmployee", true, true); diff --git a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad2_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad2_Spec.ts index 294e4d391a..4c60d6dbce 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad2_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad2_Spec.ts @@ -15,10 +15,12 @@ describe("JSObjects OnLoad Actions tests", function () { homePage.CreateNewWorkspace("JSOnLoadTest", true); }); - it("1. Tc #58 Verify JSOnPageload with ConfirmBefore calling - while imported", () => { + it("1. Bug 27594 - Tc #58 Verify JSOnPageload with ConfirmBefore calling - while imported", () => { homePage.ImportApp("ImportApps/JSOnLoadImport.json", "JSOnLoadTest"); cy.wait("@importNewApplication").then(() => { agHelper.Sleep(); + + // This will fill in credentials and test the datasource dataSources.ReconnectSingleDSNAssert("MySQL-Ds", "MySQL"); }); AssertJSOnPageLoad("runSpaceCraftImages", true); diff --git a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JsOnLoad3_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JsOnLoad3_Spec.ts index f74de2b94e..be966ba7cf 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JsOnLoad3_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/JsOnLoad3_Spec.ts @@ -10,6 +10,7 @@ import { apiPage, dataSources, } from "../../../../support/Objects/ObjectsCore"; + let dsName: any, jsName: any; describe("JSObjects OnLoad Actions tests", function () { @@ -36,14 +37,14 @@ describe("JSObjects OnLoad Actions tests", function () { "Quotes", 30000, ); - apiPage.ToggleConfirmBeforeRunningApi(true); + apiPage.ToggleConfirmBeforeRunning(true); apiPage.CreateAndFillApi( datasourceFormData["randomTrumpApi"], "WhatTrumpThinks", 30000, ); - apiPage.ToggleConfirmBeforeRunningApi(true); + apiPage.ToggleConfirmBeforeRunning(true); }); jsEditor.CreateJSObject( `export default { @@ -197,7 +198,7 @@ describe("JSObjects OnLoad Actions tests", function () { apiPage.CreateAndFillApi(datasourceFormData.randomCatfactUrl, "CatFacts"); }); apiPage.ToggleOnPageLoadRun(true); - apiPage.ToggleConfirmBeforeRunningApi(true); + apiPage.ToggleConfirmBeforeRunning(true); entityExplorer.SelectEntityByName("Image1", "Widgets"); propPane.EnterJSContext( @@ -240,7 +241,7 @@ describe("JSObjects OnLoad Actions tests", function () { 30000, ); //apiPage.OnPageLoadRun(true); //OnPageLoad made true after mapping to JSONForm - apiPage.ToggleConfirmBeforeRunningApi(true); + apiPage.ToggleConfirmBeforeRunning(true); dataSources.CreateQueryFromOverlay( dsName, @@ -341,7 +342,7 @@ describe("JSObjects OnLoad Actions tests", function () { ); //callBooks confirmation also does not appear due to 13646 entityExplorer.SelectEntityByName("JSONForm1"); - propPane.UpdatePropertyFieldValue("Source data", "{{getBooks.data}}"); + propPane.EnterJSContext("sourcedata", "{{getBooks.data}}", true, false); //this toast is not coming due to existing JSON date errors but its made true at API //agHelper.ValidateToastMessage("[getBooks] will be executed automatically on page load"); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts index 03cf3d42ff..eb3f8eb80b 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts @@ -66,15 +66,15 @@ describe("Test Postgres number of connections on page load + Bug 11572, Bug 1120 }); }); - it.skip("3. Bind queries to select widget", () => { - for (let i = 1; i <= 10; i++) { + it("3. Bind queries to select widget", () => { + for (let i = 1; i < 10; i++) { entityExplorer.DragDropWidgetNVerify( "selectwidget", - i * 50 + 50, - i * 50 + 200, + i * 1.5 * 50 + 100, + i * 1.5 * 50 + 50, ); - propPane.UpdatePropertyFieldValue( - "Options", + propPane.EnterJSContext( + "Source Data", "{{Query_" + i + ".data.map( (obj) =>{ return {'label': obj.table_name, 'value': obj.table_name }})}}", @@ -83,6 +83,7 @@ describe("Test Postgres number of connections on page load + Bug 11572, Bug 1120 "Default selected value", "{{Query_" + i + ".data[" + (i - 1) + "].table_name}}", ); + propPane.EnterJSContext("Value key", "value"); assertHelper.AssertNetworkStatus("@updateLayout", 200); } }); @@ -174,8 +175,8 @@ describe("Test Postgres number of connections on page load + Bug 11572, Bug 1120 deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName_1, 200); - dataSources.DeleteDatasouceFromWinthinDS(dsName_2, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName_1, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName_2, 200); }, ); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Array_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Array_Spec.ts index cc413d990e..35b5d1121b 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Array_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Array_Spec.ts @@ -30,19 +30,12 @@ describe("Array Datatype tests", function () { agHelper.RenameWithInPane("createTable"); dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.arraytypes"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.arraytypes"); //Creating SELECT query - arraytypes + Bug 14493 entityExplorer.ActionTemplateMenuByEntityName( "public.arraytypes", - "SELECT", + "Select", ); agHelper.RenameWithInPane("selectRecords"); dataSources.RunQuery(); @@ -152,6 +145,8 @@ describe("Array Datatype tests", function () { agHelper.ClickButton("Update"); agHelper.AssertElementAbsence(locators._toastMsg); //Assert that Update did not fail agHelper.AssertElementVisibility(locators._buttonByText("Run UpdateQuery")); + table.WaitUntilTableLoad(); + agHelper.Sleep(5000); //some more time for rows to rearrange! table.ReadTableRowColumnData(1, 0, "v1", 2000).then(($cellData) => { expect($cellData).to.eq("3"); }); @@ -541,14 +536,14 @@ describe("Array Datatype tests", function () { "Verify Deletion of all created queries & Deletion of datasource", () => { //Verify Deletion of all created queries - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); //Ds Deletion deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }, ); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts index 31e2d8388e..a654fb3035 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts @@ -10,12 +10,12 @@ import { assertHelper, } from "../../../../support/Objects/ObjectsCore"; -describe.skip("Binary Datatype tests", function () { +describe("Binary Datatype tests", function () { let dsName: any, query: string, imageNameToUpload: string; before("Create DS, Importing App & setting theme", () => { agHelper.AddDsl("Datatypes/BinaryDTdsl"); - appSettings.OpenPaneAndChangeThemeColors(24, -37); + appSettings.OpenPaneAndChangeThemeColors(7, -9); dataSources.CreateDataSource("Postgres"); cy.get("@dsName").then(($dsName) => { dsName = $dsName; @@ -27,20 +27,13 @@ describe.skip("Binary Datatype tests", function () { dataSources.CreateQueryAfterDSSaved(query, "createTable"); dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.binarytype"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.binarytype"); //Creating SELECT query - binarytype + Bug 14493 query = `SELECT binarytype.serialid, binarytype.imagename, encode(binarytype.existingimage, 'escape') as "OldImage", encode(binarytype.newimage, 'escape') as "NewImage" from public."binarytype";`; entityExplorer.ActionTemplateMenuByEntityName( "public.binarytype", - "SELECT", + "Select", ); dataSources.RunQuery(); agHelper @@ -74,38 +67,42 @@ describe.skip("Binary Datatype tests", function () { entityExplorer.ExpandCollapseEntity("Queries/JS", false); entityExplorer.ExpandCollapseEntity(dsName, false); - }); - - it("3. Inserting record - binarytype", () => { - imageNameToUpload = "Datatypes/Bridge.jpg"; entityExplorer.SelectEntityByName("Page1"); deployMode.DeployApp(); table.WaitForTableEmpty(); //asserting table is empty before inserting! - agHelper.ClickButton("Run InsertQuery"); - agHelper.AssertElementVisibility(locators._modal); - - agHelper.ClickButton("Select New Image"); - agHelper.UploadFile(imageNameToUpload); - - agHelper.ClickButton("Insert"); - agHelper.AssertElementAbsence(locators._toastMsg); //Assert that Insert did not fail - agHelper.AssertElementVisibility(locators._buttonByText("Run InsertQuery")); - agHelper.AssertElementAbsence(locators._btnSpinner, 10000); //for the update row to appear at last - table.WaitUntilTableLoad(); - agHelper.Sleep(3000); //some more time for all rows with images to be populated - table.ReadTableRowColumnData(0, 0).then(($cellData) => { - expect($cellData).to.eq("1"); //asserting serial column is inserting fine in sequence - }); - table.ReadTableRowColumnData(0, 1, "v1", 200).then(($cellData) => { - expect($cellData).to.eq("Bridge.jpg"); - }); - table.AssertTableRowImageColumnIsLoaded(0, 2).then(($oldimage) => { - table.AssertTableRowImageColumnIsLoaded(0, 3).then(($newimage) => { - expect($oldimage).to.eq($newimage); - }); - }); }); + //Timing out a lot in CI, hence skipped, Insert verified also in next case + // it.skip("3. Inserting record - binarytype", () => { + // imageNameToUpload = "Datatypes/Bridge.jpg"; + // // entityExplorer.SelectEntityByName("Page1"); + // // deployMode.DeployApp(); + // // table.WaitForTableEmpty(); //asserting table is empty before inserting! + // agHelper.ClickButton("Run InsertQuery"); + // agHelper.AssertElementVisibility(locators._modal); + + // agHelper.ClickButton("Select New Image"); + // agHelper.UploadFile(imageNameToUpload); + + // agHelper.ClickButton("Insert"); + // agHelper.AssertElementAbsence(locators._toastMsg); //Assert that Insert did not fail + // agHelper.AssertElementVisibility(locators._buttonByText("Run InsertQuery")); + // agHelper.AssertElementAbsence(locators._btnSpinner, 10000); //for the update row to appear at last + // table.WaitUntilTableLoad(); + // agHelper.Sleep(3000); //some more time for all rows with images to be populated + // table.ReadTableRowColumnData(0, 0).then(($cellData) => { + // expect($cellData).to.eq("1"); //asserting serial column is inserting fine in sequence + // }); + // table.ReadTableRowColumnData(0, 1, "v1", 200).then(($cellData) => { + // expect($cellData).to.eq("Bridge.jpg"); + // }); + // table.AssertTableRowImageColumnIsLoaded(0, 2).then(($oldimage) => { + // table.AssertTableRowImageColumnIsLoaded(0, 3).then(($newimage) => { + // expect($oldimage).to.eq($newimage); + // }); + // }); + // }); + it("4. Inserting another record - binarytype", () => { imageNameToUpload = "Datatypes/Georgia.jpeg"; @@ -177,7 +174,7 @@ describe.skip("Binary Datatype tests", function () { agHelper.AssertElementVisibility(locators._buttonByText("Run UpdateQuery")); agHelper.AssertElementAbsence(locators._btnSpinner, 20000); //for the update row to appear at last table.WaitUntilTableLoad(); - agHelper.Sleep(10000); //some more time for rows to rearrange! + agHelper.Sleep(14000); //some more time for rows to rearrange! table.ReadTableRowColumnData(2, 0, "v1", 2000).then(($cellData) => { expect($cellData).to.eq("2"); //asserting serial column is inserting fine in sequence }); @@ -378,6 +375,7 @@ describe.skip("Binary Datatype tests", function () { entityExplorer.ExpandCollapseEntity("Queries/JS", false); }); + //Since query delete & Postgress DS delete is covered in other specs, commenting below code // after( // "Validate Drop of the Newly Created - binarytype - Table & Verify Deletion of all created queries", // () => { @@ -400,7 +398,7 @@ describe.skip("Binary Datatype tests", function () { // entityExplorer.ExpandCollapseEntity("Datasources", false); // //Delete all queries - // dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + // dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists // entityExplorer.ExpandCollapseEntity("Queries/JS"); // entityExplorer.DeleteAllQueriesForDB(dsName); @@ -408,7 +406,7 @@ describe.skip("Binary Datatype tests", function () { // deployMode.DeployApp(); // deployMode.NavigateBacktoEditor(); // entityExplorer.ExpandCollapseEntity("Queries/JS"); - // dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + // dataSources.DeleteDatasourceFromWithinDS(dsName, 200); // }, // ); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/BooleanEnum_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/BooleanEnum_Spec.ts index aa6cd86494..06e7fcd656 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/BooleanEnum_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/BooleanEnum_Spec.ts @@ -31,20 +31,12 @@ describe("Boolean & Enum Datatype tests", function () { dataSources.CreateQueryFromOverlay(dsName, query, "createTable"); dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); //Clicking Create Query from Active DS is already expanding ds - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.boolenumtypes"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.boolenumtypes"); //Select query: entityExplorer.ActionTemplateMenuByEntityName( "public.boolenumtypes", - "SELECT", + "Select", ); agHelper.RenameWithInPane("selectRecords"); dataSources.RunQuery(); @@ -251,7 +243,7 @@ describe("Boolean & Enum Datatype tests", function () { entityExplorer.ExpandCollapseEntity("Datasources", false); //Delete queries - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); @@ -259,7 +251,7 @@ describe("Boolean & Enum Datatype tests", function () { deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }, ); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Character_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Character_Spec.ts index ae16cbb321..7288f28cf1 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Character_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Character_Spec.ts @@ -28,20 +28,12 @@ describe("Character Datatype tests", function () { agHelper.RenameWithInPane("createTable"); agHelper.FocusElement(locators._codeMirrorTextArea); dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.chartypes"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.chartypes"); }); it("2. Creating SELECT query - chartypes + Bug 14493", () => { query = `SELECT *, char_length("AsMany") as "AsMany-Len", char_length("Unlimited") as "Unlimited-Len" FROM public."chartypes" as charT LIMIT 10;`; - entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "SELECT"); + entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "Select"); dataSources.RunQuery(); agHelper .GetText(dataSources._noRecordFound) @@ -55,7 +47,7 @@ describe("Character Datatype tests", function () { it("3. Creating all queries - chartypes", () => { query = `INSERT INTO public."chartypes" ("One(1)", "AsMany", "Limited(4)", "Unlimited") VALUES ({{Insertone.text}}, {{Insertasmany.text}}, {{Insertlimited.text}}::varchar(4), {{Insertunlimited.text}});`; - entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "INSERT"); + entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "Insert"); dataSources.EnterQuery(query); agHelper.RenameWithInPane("insertRecord"); @@ -65,22 +57,22 @@ describe("Character Datatype tests", function () { "Limited(4)" = {{Updatelimited.text}}::varchar(4), "Unlimited" = {{Updateunlimited.text}} WHERE serialid = {{Table1.selectedRow.serialid}};`; - entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "UPDATE"); + entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "Update"); dataSources.EnterQuery(query); agHelper.RenameWithInPane("updateRecord"); query = `DELETE FROM public."chartypes"`; - entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "DELETE"); + entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "Delete"); dataSources.EnterQuery(query); agHelper.RenameWithInPane("deleteAllRecords"); query = `drop table public."chartypes"`; - entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "DELETE"); + entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "Delete"); dataSources.EnterQuery(query); agHelper.RenameWithInPane("dropTable"); query = `DELETE FROM public."chartypes" WHERE serialId = {{Table1.selectedRow.serialid}};`; - entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "DELETE"); + entityExplorer.ActionTemplateMenuByEntityName("public.chartypes", "Delete"); dataSources.EnterQuery(query); agHelper.RenameWithInPane("deleteRecord"); @@ -358,12 +350,12 @@ describe("Character Datatype tests", function () { }); it("15. Verify Deletion of the datasource after all created queries are deleted", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); //ProductLines, Employees pages are still using this ds + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); //ProductLines, Employees pages are still using this ds }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/DateTime_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/DateTime_Spec.ts index 8d90901710..5fd7bdfb42 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/DateTime_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/DateTime_Spec.ts @@ -31,15 +31,7 @@ describe("DateTime Datatype tests", function () { agHelper.RenameWithInPane("createTable"); agHelper.FocusElement(locators._codeMirrorTextArea); dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.datetimetypes"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.datetimetypes"); }); it("2. Creating SELECT query - datetimetypes + Bug 14493", () => { @@ -51,7 +43,7 @@ describe("DateTime Datatype tests", function () { TO_CHAR (datetimeT.dater, 'W') as "WentityExplorer.k of Month" FROM public."datetimetypes" as datetimeT;`; entityExplorer.ActionTemplateMenuByEntityName( "public.datetimetypes", - "SELECT", + "Select", ); dataSources.RunQuery(); agHelper @@ -66,7 +58,7 @@ describe("DateTime Datatype tests", function () { VALUES('{{Insertts.text}}', '{{Inserttstz.text}}', '{{Insertdater.text}}', '{{Inserttimer.text}}', '{{Insertintervaler.text}}');`; entityExplorer.ActionTemplateMenuByEntityName( "public.datetimetypes", - "INSERT", + "Insert", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("insertRecord"); @@ -77,7 +69,7 @@ describe("DateTime Datatype tests", function () { "intervaler" = '{{Updateintervaler.text}}' WHERE serialid = {{Table1.selectedRow.serialid}};`; entityExplorer.ActionTemplateMenuByEntityName( "public.datetimetypes", - "UPDATE", + "Update", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("updateRecord"); @@ -86,7 +78,7 @@ describe("DateTime Datatype tests", function () { query = `DELETE FROM public."datetimetypes"`; entityExplorer.ActionTemplateMenuByEntityName( "public.datetimetypes", - "DELETE", + "Delete", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("deleteAllRecords"); @@ -94,7 +86,7 @@ describe("DateTime Datatype tests", function () { query = `drop table public."datetimetypes"`; entityExplorer.ActionTemplateMenuByEntityName( "public.datetimetypes", - "DELETE", + "Delete", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("dropTable"); @@ -103,7 +95,7 @@ describe("DateTime Datatype tests", function () { WHERE serialId = {{Table1.selectedRow.serialid}};`; entityExplorer.ActionTemplateMenuByEntityName( "public.datetimetypes", - "DELETE", + "Delete", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("deleteRecord"); @@ -117,7 +109,7 @@ describe("DateTime Datatype tests", function () { EXTRACT (MINUTE FROM INTERVAL '5 hours 21 minutes');`; entityExplorer.ActionTemplateMenuByEntityName( "public.datetimetypes", - "SELECT", + "Select", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("intervalRecords"); @@ -338,12 +330,12 @@ describe("DateTime Datatype tests", function () { }); it("12. Verify Deletion of the datasource after all created queries are deleted", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); //ProductLines, EmployentityExplorer.s pages are still using this ds + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); //ProductLines, EmployentityExplorer.s pages are still using this ds }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Json_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Json_Spec.ts index d31b48e9d9..3d1097217d 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Json_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Json_Spec.ts @@ -40,18 +40,11 @@ describe("Json & JsonB Datatype tests", function () { dataSources.EnterQuery(query); agHelper.RenameWithInPane("createTable"); dataSources.RunQuery(); - entityExplorer.SelectEntityByName(dsName, "Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.jsonbooks"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.jsonbooks"); }); it("2. Creating SELECT query - jsonbooks + Bug 14493", () => { - entityExplorer.ActionTemplateMenuByEntityName("public.jsonbooks", "SELECT"); + entityExplorer.ActionTemplateMenuByEntityName("public.jsonbooks", "Select"); agHelper.RenameWithInPane("selectRecords"); dataSources.RunQuery(); agHelper @@ -168,6 +161,7 @@ describe("Json & JsonB Datatype tests", function () { agHelper.ClickButton("Update"); agHelper.AssertElementAbsence(locators._toastMsg); //Assert that Update did not fail agHelper.AssertElementVisibility(locators._buttonByText("Run UpdateQuery")); + agHelper.Sleep(5000); //Allowing time for update to be success for CI flaky behavior table.ReadTableRowColumnData(1, 0, "v1", 2000).then(($cellData) => { expect($cellData).to.eq("3"); }); @@ -319,21 +313,13 @@ describe("Json & JsonB Datatype tests", function () { expect($cellData).to.eq("0"); //Success response for dropped table! }); entityExplorer.ExpandCollapseEntity("Queries/JS", false); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementAbsence( - entityExplorer._entityNameInExplorer("public.jsonbooks"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.jsonbooks", false); entityExplorer.ExpandCollapseEntity(dsName, false); entityExplorer.ExpandCollapseEntity("Datasources", false); }); it("13. Verify Deletion of all created queries", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); }); @@ -362,21 +348,13 @@ describe("Json & JsonB Datatype tests", function () { agHelper.RenameWithInPane("createTable"); dataSources.RunQuery(); - entityExplorer.SelectEntityByName(dsName, "Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - entityExplorer.ExpandCollapseEntity(dsName); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.jsonBbooks"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.jsonBbooks"); }); it("16. Creating SELECT query - jsonBbooks + Bug 14493", () => { entityExplorer.ActionTemplateMenuByEntityName( "public.jsonBbooks", - "SELECT", + "Select", ); agHelper.RenameWithInPane("selectRecords"); dataSources.RunQuery(); @@ -681,21 +659,13 @@ describe("Json & JsonB Datatype tests", function () { expect($cellData).to.eq("0"); //Success response for dropped table! }); entityExplorer.ExpandCollapseEntity("Queries/JS", false); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementAbsence( - entityExplorer._entityNameInExplorer("public.jsonBbooks"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.jsonBbooks", false); entityExplorer.ExpandCollapseEntity(dsName, false); entityExplorer.ExpandCollapseEntity("Datasources", false); }); it("27. Verify Deletion of all created queries", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); }); @@ -706,6 +676,6 @@ describe("Json & JsonB Datatype tests", function () { deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Numeric_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Numeric_Spec.ts index fc76280882..0299fe89fd 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Numeric_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Numeric_Spec.ts @@ -29,21 +29,13 @@ describe("Numeric Datatype tests", function () { agHelper.RenameWithInPane("createTable"); agHelper.FocusElement(locators._codeMirrorTextArea); dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.numerictypes"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.numerictypes"); }); it("2. Creating SELECT query - numerictypes + Bug 14493", () => { entityExplorer.ActionTemplateMenuByEntityName( "public.numerictypes", - "SELECT", + "Select", ); dataSources.RunQuery(); agHelper @@ -57,7 +49,7 @@ describe("Numeric Datatype tests", function () { VALUES ({{Insertbigint.text}}, {{Insertdecimal.text}}, {{Insertnumeric.text}})`; entityExplorer.ActionTemplateMenuByEntityName( "public.numerictypes", - "INSERT", + "Insert", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("insertRecord"); @@ -69,7 +61,7 @@ describe("Numeric Datatype tests", function () { WHERE serialid = {{Table1.selectedRow.serialid}};`; entityExplorer.ActionTemplateMenuByEntityName( "public.numerictypes", - "UPDATE", + "Update", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("updateRecord"); @@ -77,7 +69,7 @@ describe("Numeric Datatype tests", function () { query = `DELETE FROM public."numerictypes"`; entityExplorer.ActionTemplateMenuByEntityName( "public.numerictypes", - "DELETE", + "Delete", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("deleteAllRecords"); @@ -85,7 +77,7 @@ describe("Numeric Datatype tests", function () { query = `drop table public."numerictypes"`; entityExplorer.ActionTemplateMenuByEntityName( "public.numerictypes", - "DELETE", + "Delete", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("dropTable"); @@ -94,7 +86,7 @@ describe("Numeric Datatype tests", function () { WHERE serialId ={{Table1.selectedRow.serialid}}`; entityExplorer.ActionTemplateMenuByEntityName( "public.numerictypes", - "DELETE", + "Delete", ); dataSources.EnterQuery(query); agHelper.RenameWithInPane("deleteRecord"); @@ -303,26 +295,18 @@ describe("Numeric Datatype tests", function () { expect($cellData).to.eq("0"); //Success response for dropped table! }); entityExplorer.ExpandCollapseEntity("Queries/JS", false); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementAbsence( - entityExplorer._entityNameInExplorer("public.numerictypes"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.numerictypes", false); entityExplorer.ExpandCollapseEntity(dsName, false); entityExplorer.ExpandCollapseEntity("Datasources", false); }); it("15. Verify Deletion of the datasource after all created queries are deleted", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); //ProductLines, Employees pages are still using this ds + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); //ProductLines, Employees pages are still using this ds }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/UUID_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/UUID_Spec.ts index 8e36de7429..2c805d81a3 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/UUID_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/UUID_Spec.ts @@ -40,18 +40,11 @@ describe("UUID Datatype tests", function () { dataSources.EnterQuery(query); agHelper.RenameWithInPane("createTable"); dataSources.RunQuery(); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("public.uuidtype"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "public.uuidtype"); }); it("3. Creating SELECT query - uuidtype + Bug 14493", () => { - entityExplorer.ActionTemplateMenuByEntityName("public.uuidtype", "SELECT"); + entityExplorer.ActionTemplateMenuByEntityName("public.uuidtype", "Select"); dataSources.RunQuery(); agHelper .GetText(dataSources._noRecordFound) @@ -189,6 +182,7 @@ describe("UUID Datatype tests", function () { locators._buttonByText("Run UpdateQuery"), ); table.WaitUntilTableLoad(); + agHelper.Sleep(5000); //some more time for rows to rearrange for CI flakyness! table.ReadTableRowColumnData(2, 0).then(($cellData) => { expect($cellData).to.eq("3"); //asserting serial column is inserting fine in sequence }); @@ -390,7 +384,7 @@ describe("UUID Datatype tests", function () { }); it("15. Verify Deletion of all created queries", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Since all queries exists + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Since all queries exists entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.DeleteAllQueriesForDB(dsName); }); @@ -399,6 +393,6 @@ describe("UUID Datatype tests", function () { deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); entityExplorer.ExpandCollapseEntity("Queries/JS"); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 200); + dataSources.DeleteDatasourceFromWithinDS(dsName, 200); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/AddWidgetTableAndBind_spec.js b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/AddWidgetTableAndBind_spec.js index 277ec1e540..f317dac184 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/AddWidgetTableAndBind_spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/AddWidgetTableAndBind_spec.js @@ -7,7 +7,7 @@ import { agHelper, dataSources, } from "../../../../support/Objects/ObjectsCore"; -let datasourceName; +import { Widgets } from "../../../../support/Pages/DataSources"; describe("Addwidget from Query and bind with other widgets", function () { before(() => { @@ -33,7 +33,7 @@ describe("Addwidget from Query and bind with other widgets", function () { .invoke("text") .then((text) => { const tableRowTxt = text; - cy.get(queryEditor.suggestedTableWidget).click(); + dataSources.AddSuggestedWidget(Widgets.Table); entityExplorer.SelectEntityByName("Table1"); cy.isSelectRow(1); cy.readTableV2dataPublish("1", "0").then((tabData) => { diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/DSDocs_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/DSDocs_Spec.ts index b69619148a..d14f44e466 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/DSDocs_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/DSDocs_Spec.ts @@ -4,6 +4,7 @@ import { dataSources, entityItems, deployMode, + dataManager, } from "../../../../support/Objects/ObjectsCore"; import { DataSourceKVP } from "../../../../support/Pages/DataSources"; @@ -18,7 +19,7 @@ describe("Check datasource doc links", function () { deployMode.StubWindowNAssert( dataSources._queryDoc, "querying-postgres#create-crud-queries", - "getWorkspace", + "getPluginForm", ); }); }); @@ -31,7 +32,7 @@ describe("Check datasource doc links", function () { deployMode.StubWindowNAssert( dataSources._queryDoc, "querying-mongodb#create-queries", - "getWorkspace", + "getPluginForm", ); }); }); @@ -44,7 +45,7 @@ describe("Check datasource doc links", function () { deployMode.StubWindowNAssert( dataSources._queryDoc, "querying-mysql#create-queries", - "getWorkspace", + "getPluginForm", ); }); }); @@ -57,7 +58,7 @@ describe("Check datasource doc links", function () { deployMode.StubWindowNAssert( dataSources._queryDoc, "querying-arango-db#using-queries-in-applications", - "getWorkspace", + "getPluginForm", ); }); }); @@ -70,7 +71,69 @@ describe("Check datasource doc links", function () { deployMode.StubWindowNAssert( dataSources._queryDoc, "querying-amazon-s3#list-files", - "getWorkspace", + "getPluginForm", + ); + }); + }); + + it("6. Verify SMTP documentation opens", function () { + CreateDummyDSNSave(DataSourceKVP["SMTP"]); + cy.get("@dsName").then(($dsName) => { + dsName = $dsName; + dataSources.CreateQueryAfterDSSaved(); + deployMode.StubWindowNAssert( + dataSources._queryDoc, + "connect-data/reference/using-smtp", + "getPluginForm", + ); + }); + }); + + it("excludeForAirgap", "7. Verify Airtable documentation opens", function () { + CreateDummyDSNSave(DataSourceKVP["Airtable"]); + cy.get("@dsName").then(($dsName) => { + dsName = $dsName; + dataSources.CreateQueryAfterDSSaved(); + deployMode.StubWindowNAssert( + dataSources._queryDoc, + "airtable#create-queries", + "getPluginForm", + ); + }); + }); + + it("8. Verify Oracle documentation opens", function () { + dataSources.CreateDataSource( + "Oracle", + true, + false, + dataManager.environments[1], + ); //using mock dataset for oracle + cy.get("@dsName").then(($dsName) => { + dsName = $dsName; + dataSources.CreateQueryAfterDSSaved(); + deployMode.StubWindowNAssert( + dataSources._queryDoc, + "querying-oracle#create-queries", + "getPluginForm", + ); + }); + }); + + it("9. Verify Firestore documentation opens", function () { + dataSources.CreateDataSource( + "Firestore", + true, + false, + dataManager.environments[1], + ); //using mock dataset for oracle + cy.get("@dsName").then(($dsName) => { + dsName = $dsName; + dataSources.CreateQueryAfterDSSaved(); + deployMode.StubWindowNAssert( + dataSources._queryDoc, + "querying-firestore#understanding-commands", + "getPluginForm", ); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/GoogleSheets_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/GoogleSheets_spec.ts index 44a8013902..ca04e767d3 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/GoogleSheets_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/GoogleSheets_spec.ts @@ -4,63 +4,43 @@ import { locators, agHelper, } from "../../../../support/Objects/ObjectsCore"; -const datasource = require("../../../../locators/DatasourcesEditor.json"); describe( "excludeForAirgap", "Google Sheets datasource row objects placeholder", function () { - let queryName; - let datasourceName; let pluginName = "Google Sheets"; - let placeholderText = - '{\n "name": {{nameInput.text}},\n "dob": {{dobPicker.formattedDate}},\n "gender": {{genderSelect.selectedOptionValue}} \n}'; - //Skiiping due to open bug #18035: Should the Save button be renamed as "Save and Authorise" in case of Google sheets for datasource discard popup? - it.skip("1. Bug: 16391 - Google Sheets DS, placeholder objects keys should have quotes", function () { - // create new Google Sheets datasource + it("1. Verify GSheets dropdown options", function () { dataSources.NavigateToDSCreateNew(); - dataSources.CreatePlugIn(pluginName); - - // navigate to create query tab and create a new query - // cy.get("@saveDatasource").then((httpResponse) => { - // datasourceName = httpResponse.body.data.name; - // // clicking on new query to write a query - // cy.NavigateToQueryEditor(); - // cy.get(explorer.createNew).click(); - // cy.get("div:contains('" + datasourceName + " Query')") - // .last() - // .click(); - - // fill the create new api google sheets form - // and check for rowobject placeholder text - cy.get(datasource.gSheetsOperationDropdown).click(); - cy.get(datasource.gSheetsInsertOneOption).click(); - - cy.get(datasource.gSheetsEntityDropdown).click(); - cy.get(datasource.gSheetsSheetRowsOption).click(); - - cy.get(datasource.gSheetsCodeMirrorPlaceholder).should( - "have.text", - placeholderText, - ); - - // delete query and datasource after test is done - // cy.get("@createNewApi").then((httpResponse) => { - // queryName = httpResponse.response.body.data.name; - // cy.deleteQueryUsingContext(); - // cy.deleteDatasource(datasourceName); - // }); - //}); + dataSources.CreatePlugIn("Google Sheets"); + VerifyFunctionDropdown([ + "Read / Write / Delete | Selected google sheets", + "Read / Write / Delete | All google sheets", + "Read / Write | All google sheets", + "Read | All google sheets", + ]); + dataSources.SaveDSFromDialog(false); }); + function VerifyFunctionDropdown(scopeOptions: string[]) { + agHelper.GetNClick(dataSources._gsScopeDropdown); + cy.get(dataSources._gsScopeOptions).then(function ($ele) { + expect($ele.eq(0).text()).to.be.oneOf(scopeOptions); + expect($ele.eq(1).text()).to.be.oneOf(scopeOptions); + expect($ele.eq(2).text()).to.be.oneOf(scopeOptions); + }); + agHelper.GetNClick(dataSources._gsScopeDropdown); + } + it("2. Bug # 25004 - Verify Google Sheets documentation opens", function () { dataSources.NavigateToDSCreateNew(); dataSources.CreatePlugIn(pluginName); + agHelper.Sleep(); //for plugin page to settle deployMode.StubWindowNAssert( locators._learnMore, "querying-google-sheets#create-queries", - "getWorkspace", + "getPluginForm", ); agHelper.GetNClick(locators._visibleTextSpan("Don't save")); agHelper.Sleep(); diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts similarity index 94% rename from app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo_Spec.ts rename to app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts index d3eed3d7b2..8ecc449772 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts @@ -312,15 +312,7 @@ describe("Validate Mongo Query Pane Validations", () => { entityType: entityItems.Query, }); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("AuthorNAwards"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "AuthorNAwards"); }); it("3. Validate 'Find' record from new collection & verify query response", () => { @@ -336,7 +328,7 @@ describe("Validate Mongo Query Pane Validations", () => { it("4. Validate 'Find by ID' record from new collection & verify query response", () => { entityExplorer.ActionTemplateMenuByEntityName( "AuthorNAwards", - "Find by ID", + "Find by id", ); dataSources.ValidateNSelectDropdown("Commands", "Find document(s)"); agHelper.EnterValue(`{"_id": ObjectId("51df07b094c6acd67e492f41")}`, { @@ -696,15 +688,7 @@ describe("Validate Mongo Query Pane Validations", () => { action: "Delete", entityType: entityItems.Query, }); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementAbsence( - entityExplorer._entityNameInExplorer("AuthorNAwards"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "AuthorNAwards", false); }); it("18. Verify application does not break when user runs the query with wrong collection name", function () { @@ -800,15 +784,7 @@ describe("Validate Mongo Query Pane Validations", () => { entityType: entityItems.Query, }); //Execute a find query on this collection to see if dates are fetched properly - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer("BirthNDeath"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "BirthNDeath"); entityExplorer.ActionTemplateMenuByEntityName("BirthNDeath", "Find"); dataSources.ValidateNSelectDropdown("Commands", "Find document(s)"); @@ -827,16 +803,7 @@ describe("Validate Mongo Query Pane Validations", () => { dataSources.EnterQuery(dropCollection); agHelper.FocusElement(locators._codeMirrorTextArea); dataSources.RunQuery(); - - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementAbsence( - entityExplorer._entityNameInExplorer("BirthNDeath"), - ); + dataSources.AssertTableInVirtuosoList(dsName, "BirthNDeath", false); }); it("20. Verify Deletion of the datasource", () => { @@ -846,7 +813,7 @@ describe("Validate Mongo Query Pane Validations", () => { // assertHelper.AssertNetworkStatus("@deletePage", 200); deployMode.DeployApp(); deployMode.NavigateBacktoEditor(); - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); //Friends pages are still using this ds + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //Friends pages are still using this ds }); function GenerateCRUDNValidateDeployPage( @@ -862,7 +829,7 @@ describe("Validate Mongo Query Pane Validations", () => { assertHelper.AssertNetworkStatus("@postExecute", 200); assertHelper.AssertNetworkStatus("@updateLayout", 200); - agHelper.GetNClick(dataSources._visibleTextSpan("Got it")); + agHelper.ClickButton("Got it"); deployMode.DeployApp(); //Validating loaded table diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo_Spec.js b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo_Spec.js index 810e41a30a..db662156bb 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo_Spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo_Spec.js @@ -1,6 +1,5 @@ const queryLocators = require("../../../../locators/QueryEditor.json"); const generatePage = require("../../../../locators/GeneratePage.json"); -const datasource = require("../../../../locators/DatasourcesEditor.json"); const formControls = require("../../../../locators/FormControl.json"); import { @@ -10,6 +9,7 @@ import { dataSources, entityItems, assertHelper, + locators, } from "../../../../support/Objects/ObjectsCore"; let datasourceName; @@ -27,18 +27,14 @@ describe("Validate Mongo query commands", function () { // }); before("Creates a new Mongo datasource", function () { - cy.NavigateToDatasourceEditor(); - cy.get(datasource.MongoDB).click(); - cy.fillMongoDatasourceForm(); - cy.generateUUID().then((uid) => { - datasourceName = `Mongo CRUD ds ${uid}`; - cy.renameDatasource(datasourceName); + dataSources.CreateDataSource("Mongo"); + dataSources.CreateQueryAfterDSSaved(); + cy.get("@dsName").then(($dsName) => { + datasourceName = $dsName; }); - cy.testSaveDatasource(); }); it("1. Validate Raw query command, run and then delete the query", function () { - cy.NavigateToActiveDSQueryPane(datasourceName); // cy.get("@getPluginForm").should( // "have.nested.property", // "response.body.responseMeta.status", @@ -50,11 +46,7 @@ describe("Validate Mongo query commands", function () { "Find document(s)", "Raw", ); - cy.get(queryLocators.templateMenu).click(); - cy.typeValueNValidate( - '{"find": "listingAndReviews","limit": 10}', - formControls.rawBody, - ); + agHelper.GetNClick(dataSources._templateMenu); // cy.get(".CodeMirror textarea") // .first() @@ -64,7 +56,9 @@ describe("Validate Mongo query commands", function () { // }); // cy.EvaluateCurrentValue(`{"find": "listingAndReviews","limit": 10}`); - cy.runQuery(); + dataSources.EnterQuery(`{"find": "listingAndReviews","limit": 10}`); + agHelper.FocusElement(locators._codeMirrorTextArea); + dataSources.RunQuery(); dataSources.CheckResponseRecordsCount(10); cy.deleteQueryUsingContext(); }); @@ -293,12 +287,7 @@ describe("Validate Mongo query commands", function () { it("8. Bug 7399: Validate Form based & Raw command based templates", function () { let id; - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(`${datasourceName}`); - cy.get("[data-testid='t--entity-item-listingAndReviews']") - .find(".t--template-menu-trigger") - .click({ force: true }); - + dataSources.AssertTableInVirtuosoList(datasourceName, "listingAndReviews"); entityExplorer.ActionTemplateMenuByEntityName("listingAndReviews", "Find"); cy.get(`${formControls.mongoCollection} .rc-select-selection-item`) @@ -376,7 +365,7 @@ describe("Validate Mongo query commands", function () { it("9. Delete the datasource after NewPage deletion is success", () => { cy.NavigateToQueryEditor(); - dataSources.DeleteDatasouceFromActiveTab(datasourceName, [200 | 409]); + dataSources.DeleteDatasouceFromActiveTab(datasourceName, [200, 409]); }); it("10. Bug 6375: Cyclic Dependency error occurs and the app crashes when the user generate table and chart from mongo query", function () { diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/MySQL_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/MySQL_Spec.ts index de4359ec7b..75ef7130f8 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/MySQL_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/MySQL_Spec.ts @@ -84,7 +84,7 @@ describe("Validate MySQL query UI flows - Bug 14054", () => { }); after("Verify Deletion of the datasource", () => { - dataSources.DeleteDatasouceFromWinthinDS(dsName, 409); + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); agHelper.ValidateToastMessage( "Cannot delete datasource since it has 1 action(s) using it.", ); //table is 1 action diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Postgres_Spec.js b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Postgres_Spec.js index 549eb775de..fcfb673a40 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Postgres_Spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Postgres_Spec.js @@ -321,6 +321,6 @@ describe("Validate CRUD queries for Postgres along with UI flow verifications", it("13. Deletes the datasource", () => { cy.NavigateToQueryEditor(); - dataSources.DeleteDatasouceFromActiveTab(datasourceName, [200 | 409]); + dataSources.DeleteDatasouceFromActiveTab(datasourceName, [200, 409]); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_1_spec.js b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_1_spec.js index b0fc5c23f1..fa4001575d 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_1_spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_1_spec.js @@ -76,11 +76,11 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", }); }); cy.wait(2000); - // agHelper.ActionContextMenuWithInPane({ - // action: "Delete", - // entityType: entityItems.Query, - // });//do not want to delete it for the sake of keeping the DS in Entity Explorer - entityExplorer.ExpandCollapseEntity(datasourceName); + + dataSources.AssertTableInVirtuosoList( + datasourceName, + "assets-test--appsmith", + ); entityExplorer.ActionTemplateMenuByEntityName( "assets-test--appsmith", @@ -513,7 +513,7 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", it("7. Validate Deletion of the Newly Created Page", () => { cy.NavigateToQueryEditor(); - dataSources.DeleteDatasouceFromWinthinDS(datasourceName, 409); + dataSources.DeleteDatasourceFromWithinDS(datasourceName, 409); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Assets-test.appsmith.com", action: "Delete", @@ -522,6 +522,6 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", }); after("Deletes the datasource", () => { - dataSources.DeleteDatasouceFromActiveTab(datasourceName, [200 | 409]); + dataSources.DeleteDatasouceFromActiveTab(datasourceName, [200, 409]); }); }); diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_2_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_2_spec.ts index 27506e2b11..ca9f57b295 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_2_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/S3_2_spec.ts @@ -169,7 +169,7 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", ); }); - it("2. Edit from S3 crud pages", function () { + it("2. Edit from S3 Deployed crud page", function () { let imageNameToUpload = "Datatypes/Bridge.jpg"; //Massachusetts let fixturePath = uid + imageNameToUpload; agHelper.ClickButton("Select Files"); //1 files selected @@ -286,7 +286,7 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", ); }); - it("3. Uploading maximum files from UI - S3 Crud page", () => { + it("3. Uploading maximum files from UI - S3 Deployed Crud page", () => { let imageNameToUpload = "Datatypes/Georgia.jpeg", bulkyId = "BulkUpload/" + uid; // Datatypes/Maine.jpeg, @@ -433,18 +433,21 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", }); }); - it("6. Verify 'Connect Widget [snipping]' functionality - S3 ", () => { + it("6. Verify Adding Suggested widget with already present widget - S3 ", () => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE); + agHelper.Sleep(2500); //allowing sometime for widget to settle down dataSources.NavigateFromActiveDS(datasourceName, true); agHelper.GetObjectName().then(($queryName) => { entityExplorer.SelectEntityByName($queryName, "Queries/JS"); dataSources.ValidateNSelectDropdown("Commands", "List files in bucket"); agHelper.UpdateCodeInput(formControls.s3BucketName, bucketName); dataSources.RunQuery(); - agHelper.ClickButton("Select widget"); //Binding to dragDropped table - agHelper.AssertElementVisibility(dataSources._snippingBanner); - agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.TABLE)); - entityExplorer.SelectEntityByName("Table1", "Widgets"); + agHelper.Sleep(); //for CI runs + agHelper.ScrollIntoView("." + dataSources._addSuggestedExisting); + dataSources.AddSuggestedWidget( + Widgets.Table, + dataSources._addSuggestedExisting, + ); propPane.DeleteWidgetDirectlyFromPropertyPane(); entityExplorer.SelectEntityByName($queryName, "Queries/JS"); agHelper.ActionContextMenuWithInPane({ @@ -473,6 +476,7 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", ); //verify Delete File dialog appears agHelper.ClickButton("Confirm", { sleepTime: 3000 }); //wait for Delete operation to be successfull, //Verifies 8684 assertHelper.AssertNetworkExecutionSuccess("@postExecute", true); + agHelper.Sleep(2000); //for the delete to reflect in UI for CI runs agHelper.GetNAssertElementText( locators._textWidgetInDeployed, fileNameToDelete, diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/SwitchDatasource_spec.js b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/SwitchDatasource_spec.js index a5dd4e9089..8a3f2e58b9 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/SwitchDatasource_spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/SwitchDatasource_spec.js @@ -28,11 +28,11 @@ describe("Switch datasource", function () { it("4. By switching datasources execute a query with both the datasources", function () { dataSources.CreateQueryFromActiveTab(dsName_1); - cy.get(".rc-select-show-arrow").click(); + agHelper.GetNClick(".rc-select-show-arrow"); cy.contains(".rc-select-item-option-content", dsName_2).click().wait(1000); cy.runQuery(); // Confirm mongo datasource is not present in the switch datasources dropdown - cy.get(".rc-select-show-arrow").click(); + agHelper.GetNClick(".rc-select-show-arrow"); cy.get(".rc-select-item-option-content").should("not.have", MongoDB); }); diff --git a/app/client/cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts b/app/client/cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts index efc2181421..5c246b3d13 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts @@ -5,6 +5,11 @@ import { dataSources, dataManager, assertHelper, + draggableWidgets, + propPane, + deployMode, + locators, + table, } from "../../../support/Objects/ObjectsCore"; let dsName: any, jsonSpecies: any, offset: any, insertedRecordId: any; @@ -14,6 +19,10 @@ describe("excludeForAirgap", "Validate Airtable Ds", () => { cy.get("@dsName").then(($dsName) => { dsName = $dsName; }); + dataSources.AssertDataSourceInfo([ + "Authentication type", + "Personal access token", + ]); }); it("1. Validate List Records", () => { @@ -259,7 +268,16 @@ describe("excludeForAirgap", "Validate Airtable Ds", () => { }); }); - it("2. Create/Retrieve/Update/Delete records", () => { + it("2. Drag Drop table & verify api data to widget binding", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE); + propPane.EnterJSContext("Table data", "{{Api1.data.records}}"); + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitUntilTableLoad(0, 0, "v2"); + deployMode.NavigateBacktoEditor(); + entityExplorer.SelectEntityByName("Api1", "Queries/JS"); + }); + + it("3. Create/Retrieve/Update/Delete records", () => { let createReq = `[{"fields": { "Species_ID": "SF", "Genus": "Sigmodon", @@ -373,12 +391,10 @@ describe("excludeForAirgap", "Validate Airtable Ds", () => { action: "Delete", entityType: entityItems.Query, }); - entityExplorer.SelectEntityByName(dsName, "Datasources"); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Delete", - entityType: entityItems.Datasource, - }); - assertHelper.AssertNetworkStatus("@deleteDatasource", 200); + dataSources.DeleteDatasouceFromActiveTab(dsName, 409); //Since page was deployed in testcase #2 + deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + table.WaitForTableEmpty("v2"); + deployMode.NavigateBacktoEditor(); + dataSources.DeleteDatasouceFromActiveTab(dsName); }); }); diff --git a/app/client/cypress/e2e/Sanity/Datasources/Arango_Basic_Spec.ts b/app/client/cypress/e2e/Sanity/Datasources/Arango_Basic_Spec.ts index c686756d22..66eb812064 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/Arango_Basic_Spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/Arango_Basic_Spec.ts @@ -6,11 +6,9 @@ import { draggableWidgets, propPane, dataManager, - locators, homePage, } from "../../../support/Objects/ObjectsCore"; import { Widgets } from "../../../support/Pages/DataSources"; -import { featureFlagIntercept } from "../../../support/Objects/FeatureFlags"; describe("Validate Arango & CURL Import Datasources", () => { let dsName: any, @@ -51,15 +49,8 @@ describe("Validate Arango & CURL Import Datasources", () => { action: "Delete", entityType: entityItems.Api, }); - entityExplorer.ExpandCollapseEntity("Datasources"); - entityExplorer.ExpandCollapseEntity(dsName); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: dsName, - action: "Refresh", - }); - agHelper.AssertElementVisibility( - entityExplorer._entityNameInExplorer(collectionName), - ); + dataSources.AssertTableInVirtuosoList(dsName, collectionName); + //Add data into this newly created collection let curlDataAdd = `curl --request POST --url http://` + @@ -297,25 +288,22 @@ describe("Validate Arango & CURL Import Datasources", () => { }); it("3. Arango Widget Binding - from Suggested widget, Schema filter for Arango DS", () => { - featureFlagIntercept( - { - ab_ds_schema_enabled: true, - }, - false, - ); agHelper.RefreshPage(); entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE); propPane.AssertPropertiesDropDownCurrentValue("Table data", "Connect data"); entityExplorer.NavigateToSwitcher("Explorer"); entityExplorer.SelectEntityByName("Query6"); - dataSources.FilterAndVerifyDatasourceSchemaBySearch("country", "column"); + //dataSources.FilterAndVerifyDatasourceSchemaBySearch("countries"); + dataSources.VerifyTableSchemaOnQueryEditor(collectionName); dataSources.RunQuery(); - dataSources.AddSuggestedWidget(Widgets.Table, true); //Binding to new table from schema explorer + dataSources.AddSuggestedWidget(Widgets.Table); //Binding to new table from schema explorer propPane.AssertPropertiesDropDownCurrentValue("Table data", "Query6"); + entityExplorer.SelectEntityByName("Query6"); - agHelper.ClickButton("Select widget"); //Binding to dragDropped table - agHelper.AssertElementVisibility(dataSources._snippingBanner); - agHelper.GetNClick(locators._widgetInDeployed(draggableWidgets.TABLE)); + dataSources.AddSuggestedWidget( + Widgets.Table, + dataSources._addSuggestedExisting, + ); propPane.AssertPropertiesDropDownCurrentValue("Table data", "Query6"); }); diff --git a/app/client/cypress/e2e/Sanity/Datasources/GoogleSheetsStub_spec.ts b/app/client/cypress/e2e/Sanity/Datasources/GoogleSheetsStub_spec.ts deleted file mode 100644 index 0c91f5b030..0000000000 --- a/app/client/cypress/e2e/Sanity/Datasources/GoogleSheetsStub_spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { agHelper, dataSources } from "../../../support/Objects/ObjectsCore"; - -describe( - "excludeForAirgap", - "Google Sheets datasource test cases", - function () { - it("1. Create Google Sheets datasource", function () { - dataSources.NavigateToDSCreateNew(); - dataSources.CreatePlugIn("Google Sheets"); - VerifyFunctionDropdown([ - "Read / Write / Delete | Selected google sheets", - "Read / Write / Delete | All google sheets", - "Read / Write | All google sheets", - "Read | All google sheets", - ]); - dataSources.SaveDSFromDialog(false); - }); - - function VerifyFunctionDropdown(scopeOptions: string[]) { - agHelper.GetNClick(dataSources._gsScopeDropdown); - cy.get(dataSources._gsScopeOptions).then(function ($ele) { - expect($ele.eq(0).text()).to.be.oneOf(scopeOptions); - expect($ele.eq(1).text()).to.be.oneOf(scopeOptions); - expect($ele.eq(2).text()).to.be.oneOf(scopeOptions); - }); - agHelper.GetNClick(dataSources._gsScopeDropdown); - } - }, -); diff --git a/app/client/cypress/e2e/Sanity/Datasources/GraphQL_spec.ts b/app/client/cypress/e2e/Sanity/Datasources/GraphQL_spec.ts index 00d8d36e4b..cfe41eae8f 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/GraphQL_spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/GraphQL_spec.ts @@ -3,9 +3,11 @@ import { entityItems, apiPage, dataSources, + locators, + dataManager, + propPane, } from "../../../support/Objects/ObjectsCore"; -let appName = ""; let datasourceName = "GraphQL_DS"; let tokenToAuthorizeGraphQl = ""; let authoemail = ""; @@ -18,9 +20,9 @@ const GRAPHQL_QUERY = `query ($myid: Int!) { } }`; -const POST_ID = 4; +let POST_ID = 4; -const GRAPHQL_VARIABLES = `{ +let GRAPHQL_VARIABLES = `{ "myid": ${POST_ID} }`; @@ -45,7 +47,6 @@ const GRAPHQL_LIMIT_DATA = [ describe("GraphQL Datasource Implementation", function () { before(() => { - appName = localStorage.getItem("AppName") || ""; agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { //apiName = `${apiName}${uid}`; @@ -227,6 +228,8 @@ describe("GraphQL Datasource Implementation", function () { }); //Create Auth GraphQL to verify Delete operation + dataSources.NavigateToDSCreateNew(); + dataSources.CreatePlugIn("Authenticated GraphQL API"); dataSources.CreateNFillAuthenticatedGraphQLDSForm( datasourceName, "Authorization", @@ -249,6 +252,92 @@ describe("GraphQL Datasource Implementation", function () { }); }); + it("6. Validate Authenticated GraphQL with Empty body & then Save as Datasource + Bug #26873", () => { + POST_ID = 5; + GRAPHQL_VARIABLES = `{ + "myid": ${POST_ID} + }`; + dataSources.CreateDataSource("UnAuthenticatedGraphQL"); + // cy.get("@dsName").then(($dsName: any) => { + // cy.log("DS Name: " + $dsName); + // }); + + apiPage.RunAPI(false); + apiPage.ResponseStatusCheck("PE-ARG-5000"); + agHelper.Sleep(3500); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.isExecutionSuccess).to.eq(false); + expect(interception.response.body.data.body).to.contains( + "Your GraphQL query body is empty. Please edit the 'Body' tab of your GraphQL API to provide a query body.", + ); + }); + + apiPage.SelectPaneTab("Authentication"); + agHelper.ClickButton("Save as datasource"); + + agHelper.AssertText( + locators._inputFieldByName("URL") + "//" + locators._inputField, + "val", + dataManager.dsValues[ + dataManager.defaultEnviorment + ].GraphqlApiUrl_TED.replace("/graphql", ""), + ); + // dataSources.SaveDSFromDialog(false); //verifies bug #26873, to uncomment below once bug is fixed + // cy.get("@dsName").then(($dsName: any) => { + // entityExplorer.SelectEntityByName($dsName); + // apiPage.SelectPaneTab("Authentication"); + // agHelper.ClickButton("Save as datasource"); + // }); + dataSources.SaveDatasource(); + agHelper.ValidateToastMessage("datasource created"); + agHelper.AssertElementVisibility(locators._buttonByText("Edit datasource")); + apiPage.SelectPaneTab("Body"); + dataSources.UpdateGraphqlQueryAndVariable({ + query: GRAPHQL_QUERY, + variable: GRAPHQL_VARIABLES, + }); + apiPage.RunAPI(); + agHelper.ClickButton("Edit datasource"); + dataSources.AssertDataSourceInfo([ + dataManager.dsValues[ + dataManager.defaultEnviorment + ].GraphqlApiUrl_TED.replace("/graphql", ""), + "content-type", + "application/json", + "No", + ]); + agHelper.ClickButton("Edit"); + dataSources.ValidateNSelectDropdown( + "Authentication type", + "None", + "OAuth 2.0", + ); + propPane.AssertPropertiesDropDownValues("Grant type", [ + "Client Credentials", + "Authorization Code", + ]); + + propPane.AssertPropertiesDropDownValues("Add Access Token To", [ + "Request Header", + "Request Header", + ]); + agHelper.AssertElementVisibility( + locators._visibleTextDiv("Datasource not authorized"), + ); + agHelper.ClickButton("Cancel"); + dataSources.AssertDatasourceSaveModalVisibilityAndSave(false); + + //verify Same ds info are present that was present before editing the DS: + dataSources.AssertDataSourceInfo([ + dataManager.dsValues[ + dataManager.defaultEnviorment + ].GraphqlApiUrl_TED.replace("/graphql", ""), + "content-type", + "application/json", + "No", + ]); + }); + function RunNValidateGraphQL() { apiPage.RunAPI(false); apiPage.ResponseStatusCheck("200 OK"); diff --git a/app/client/cypress/e2e/Sanity/Datasources/MockDBs_Spec.ts b/app/client/cypress/e2e/Sanity/Datasources/MockDBs_Spec.ts index 348447b359..7cd4ac49dc 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/MockDBs_Spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/MockDBs_Spec.ts @@ -12,43 +12,7 @@ describe( "excludeForAirgap", "Validate Mock Query Active Ds querying & count", () => { - it("1. Create Query from Mock Mongo DB & verify active queries count", () => { - dataSources.CreateMockDB("Movies").then((mockDBName) => { - dsName = mockDBName; - cy.log("Mock DB Name: " + mockDBName); - - // delay is introduced so that structure fetch is complete before moving to query creation - // feat: #25320, new query created for mock db movies, will be populated with default values - agHelper.Sleep(500); - - assertHelper.AssertNetworkStatus("@getDatasourceStructure", 200); - dataSources.CreateQueryAfterDSSaved(); - - assertHelper.AssertNetworkStatus("@trigger"); - dataSources.ValidateNSelectDropdown("Commands", "Find document(s)"); - dataSources.ValidateNSelectDropdown("Collection", "movies"); - dataSources.RunQueryNVerifyResponseViews(1, false); - dataSources.NavigateToActiveTab(); - agHelper - .GetText(dataSources._queriesOnPageText(mockDBName)) - .then(($queryCount) => - expect($queryCount).to.eq("1 query on this page"), - ); - - entityExplorer.CreateNewDsQuery(mockDBName); - dataSources.ValidateNSelectDropdown("Commands", "Find document(s)"); - dataSources.ValidateNSelectDropdown("Collection", "movies"); - dataSources.RunQueryNVerifyResponseViews(1, false); - dataSources.NavigateToActiveTab(); - agHelper - .GetText(dataSources._queriesOnPageText(mockDBName)) - .then(($queryCount) => - expect($queryCount).to.eq("2 queries on this page"), - ); - }); - }); - - it("2. Create Query from Mock Postgres DB & verify active queries count", () => { + it("1. Create Query from Mock Postgres DB & verify active queries count", () => { dataSources.CreateMockDB("Users").then((mockDBName) => { dsName = mockDBName; cy.log("Mock DB Name: " + mockDBName); @@ -81,6 +45,43 @@ describe( }); }); + it("2. Create Query from Mock Mongo DB & verify active queries count", () => { + dataSources.CreateMockDB("Movies").then((mockDBName) => { + dsName = mockDBName; + cy.log("Mock DB Name: " + mockDBName); + + // delay is introduced so that structure fetch is complete before moving to query creation + // feat: #25320, new query created for mock db movies, will be populated with default values + agHelper.Sleep(500); + + assertHelper.AssertNetworkStatus("@getDatasourceStructure", 200); + dataSources.CreateQueryAfterDSSaved(); + + assertHelper.AssertNetworkStatus("@trigger"); + dataSources.ValidateNSelectDropdown("Commands", "Find document(s)"); + agHelper.Sleep(2000); //for movies collection to load & populate in dropdown + dataSources.ValidateNSelectDropdown("Collection", "movies"); + dataSources.RunQueryNVerifyResponseViews(1, false); + dataSources.NavigateToActiveTab(); + agHelper + .GetText(dataSources._queriesOnPageText(mockDBName)) + .then(($queryCount) => + expect($queryCount).to.eq("1 query on this page"), + ); + + entityExplorer.CreateNewDsQuery(mockDBName); + dataSources.ValidateNSelectDropdown("Commands", "Find document(s)"); + dataSources.ValidateNSelectDropdown("Collection", "movies"); + dataSources.RunQueryNVerifyResponseViews(1, false); + dataSources.NavigateToActiveTab(); + agHelper + .GetText(dataSources._queriesOnPageText(mockDBName)) + .then(($queryCount) => + expect($queryCount).to.eq("2 queries on this page"), + ); + }); + }); + afterEach(() => { entityExplorer.ExpandCollapseEntity("Queries/JS"); entityExplorer.ActionContextMenuByEntityName({ diff --git a/app/client/cypress/e2e/Sanity/Datasources/MongoDatasourceURI_spec.ts b/app/client/cypress/e2e/Sanity/Datasources/MongoDatasourceURI_spec.ts index 7904586f17..ffba267a9b 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/MongoDatasourceURI_spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/MongoDatasourceURI_spec.ts @@ -1,4 +1,8 @@ -import { agHelper, dataSources } from "../../../support/Objects/ObjectsCore"; +import { + agHelper, + dataManager, + dataSources, +} from "../../../support/Objects/ObjectsCore"; let dsName: any; @@ -20,4 +24,20 @@ describe("Create, test, save then delete a mongo datasource using URI", function dataSources.DeleteDatasouceFromActiveTab(dsName); }); }); + + it("2. Create Mongo DS with Training space in Host, Database name & Verify connection", function () { + dataSources.NavigateToDSCreateNew(); + agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + // using CreatePlugIn function instead of CreateDatasource, + // because I do not need to fill the datasource form and use the same default data + dataSources.CreatePlugIn("MongoDB"); + dsName = "Mongo" + uid; + agHelper.RenameWithInPane(dsName, false); + + dataSources.FillMongoDSForm(dataManager.defaultEnviorment, true); + dataSources.TestSaveDatasource(); + dataSources.DeleteDatasouceFromActiveTab(dsName); + }); + }); }); diff --git a/app/client/cypress/e2e/Sanity/Datasources/MongoDatasource_spec.js b/app/client/cypress/e2e/Sanity/Datasources/MongoDatasource_spec.js deleted file mode 100644 index 2a8d30e0fa..0000000000 --- a/app/client/cypress/e2e/Sanity/Datasources/MongoDatasource_spec.js +++ /dev/null @@ -1,19 +0,0 @@ -const datasource = require("../../../locators/DatasourcesEditor.json"); - -describe("Create, test, save then delete a mongo datasource", function () { - beforeEach(() => { - cy.startRoutesForDatasource(); - }); - - it("1. Create, test, save then delete a mongo datasource", function () { - cy.NavigateToDatasourceEditor(); - cy.get(datasource.MongoDB).click(); - cy.fillMongoDatasourceForm(); - cy.testSaveDeleteDatasource(); - //Create with trailing white spaces in host address and database name, test, save then delete a mongo datasource - cy.NavigateToDatasourceEditor(); - cy.get(datasource.MongoDB).click(); - cy.fillMongoDatasourceForm(true); //fills form with trailing white spaces - cy.testSaveDeleteDatasource(); - }); -}); diff --git a/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts b/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts index ad764b2ae6..a92e6694c5 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts @@ -1,4 +1,3 @@ -import { featureFlagIntercept } from "../../../support/Objects/FeatureFlags"; import { agHelper, assertHelper, @@ -10,6 +9,7 @@ import { table, dataManager, locators, + deployMode, } from "../../../support/Objects/ObjectsCore"; import { Widgets } from "../../../support/Pages/DataSources"; import oneClickBindingLocator from "../../../locators/OneClickBindingLocator"; @@ -90,12 +90,6 @@ describe("Validate MsSQL connection & basic querying with UI flows", () => { dataSources.RunQuery(); }); //agHelper.ActionContextMenuWithInPane("Delete"); Since next case can continue in same template - featureFlagIntercept( - { - ab_ds_binding_enabled: false, - }, - false, - ); agHelper.RefreshPage(); }); @@ -259,7 +253,7 @@ describe("Validate MsSQL connection & basic querying with UI flows", () => { dataSources.TestDatasource(false); agHelper.WaitUntilAllToastsDisappear(); agHelper.UpdateInputValue( - dataSources._host, + dataSources._host(), dataManager.dsValues[dataManager.defaultEnviorment].mssql_host, ); agHelper.UpdateInputValue( @@ -282,12 +276,110 @@ describe("Validate MsSQL connection & basic querying with UI flows", () => { }); }); + it("5. Add new Page and generate CRUD template using created datasource", () => { + entityExplorer.AddNewPage(); + entityExplorer.AddNewPage("Generate page with data"); + agHelper.GetNClick(dataSources._selectDatasourceDropdown); + agHelper.GetNClickByContains(dataSources._dropdownOption, dsName); + + assertHelper.AssertNetworkStatus("@getDatasourceStructure"); //Making sure table dropdown is populated + agHelper.GetNClick(dataSources._selectTableDropdown, 0, true); + agHelper.GetNClickByContains( + dataSources._dropdownOption, + "dbo.amazon_sales", + ); + + GenerateCRUDNValidateDeployPage( + "348f344247b0c1a935b1223072ef9d8a", + "CLASSIC TOY TRAIN SET TRACK CARRIAGES LIGHT" + + " ENGINE BOXED BOYS KIDS BATTERY", + "ccf", + "uniq_id", + ); + + deployMode.NavigateBacktoEditor(); + table.WaitUntilTableLoad(); + //Delete the test data + entityExplorer.ExpandCollapseEntity("Pages"); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Page2", + action: "Delete", + entityType: entityItems.Page, + }); + + //Should not be able to delete ds until app is published again + //coz if app is published & shared then deleting ds may cause issue, So! + dataSources.DeleteDatasouceFromActiveTab(dsName, 409); + agHelper.WaitUntilAllToastsDisappear(); + deployMode.DeployApp(locators._emptyPageTxt); + agHelper.Sleep(3000); + deployMode.NavigateBacktoEditor(); + }); + + it("6. Generate CRUD page from datasource present in ACTIVE section", function () { + dataSources.NavigateFromActiveDS(dsName, false); + agHelper.GetNClick(dataSources._selectTableDropdown, 0, true); + agHelper.GetNClickByContains( + dataSources._dropdownOption, + "dbo.amazon_sales", + ); + + GenerateCRUDNValidateDeployPage( + "348f344247b0c1a935b1223072ef9d8a", + "CLASSIC TOY TRAIN SET TRACK CARRIAGES LIGHT" + + " ENGINE BOXED BOYS KIDS BATTERY", + "ccf", + "uniq_id", + ); + + deployMode.NavigateBacktoEditor(); + table.WaitUntilTableLoad(); + }); + after("Verify Deletion of the datasource", () => { cy.intercept("DELETE", "/api/v1/datasources/*").as("deleteDatasource"); //Since intercept from before is not working - dataSources.DeleteDatasouceFromWinthinDS(dsName); + dataSources.DeleteDatasourceFromWithinDS(dsName, 409); //since CRUD pages are still active //dataSources.StopNDeleteContainer(containerName); //commenting to check if MsSQL specific container deletion is causing issues }); + function GenerateCRUDNValidateDeployPage( + col1Text: string, + col2Text: string, + col3Text: string, + jsonFromHeader: string, + ) { + agHelper.GetNClick(dataSources._generatePageBtn); + assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201); + agHelper.AssertContains("Successfully generated a page"); + assertHelper.AssertNetworkStatus("@postExecute", 200); + agHelper.ClickButton("Got it"); + assertHelper.AssertNetworkStatus("@updateLayout", 200); + deployMode.DeployApp(locators._widgetInDeployed("tablewidget")); + table.WaitUntilTableLoad(); + + //Validating loaded table + agHelper.AssertElementExist(dataSources._selectedRow); + table.ReadTableRowColumnData(0, 0, "v1", 2000).then(($cellData) => { + expect($cellData).to.eq(col1Text); + }); + table.ReadTableRowColumnData(0, 1, "v1", 200).then(($cellData) => { + expect($cellData).to.eq(col2Text); + }); + table.ReadTableRowColumnData(0, 2, "v1", 200).then(($cellData) => { + expect($cellData).to.eq(col3Text); + }); + + // Validating loaded JSON form + cy.xpath(locators._buttonByText("Update")).then((selector) => { + cy.wrap(selector) + .invoke("attr", "class") + .then((classes) => { + expect(classes).not.contain("bp3-disabled"); + }); + }); + dataSources.AssertJSONFormHeader(0, 0, jsonFromHeader); + } + function runQueryNValidate(query: string, columnHeaders: string[]) { dataSources.EnterQuery(query); dataSources.RunQuery(); diff --git a/app/client/cypress/e2e/Sanity/Datasources/RestApiOAuth2Validation_spec.js b/app/client/cypress/e2e/Sanity/Datasources/RestApiOAuth2Validation_spec.js deleted file mode 100644 index 5aaa93220a..0000000000 --- a/app/client/cypress/e2e/Sanity/Datasources/RestApiOAuth2Validation_spec.js +++ /dev/null @@ -1,54 +0,0 @@ -const testdata = require("../../../fixtures/testdata.json"); -const datasource = require("../../../locators/DatasourcesEditor.json"); -import * as _ from "../../../support/Objects/ObjectsCore"; - -describe("Datasource form OAuth2 client credentials related tests", function () { - it("1. Create an API with app url and save as Datasource for Client Credentials test", function () { - _.apiPage.CreateAndFillApi(testdata.appUrl, "TestOAuth"); - _.agHelper.GetNClick(_.apiPage._saveAsDS); - // agHelper.ValidateToastMessage("datasource created"); //verifying there is no error toast, Bug 14566 - }); - - it("2. Add Oauth details to datasource and save", function () { - cy.get(datasource.saveBtn).should("not.be.disabled"); - _.dataSources.AddOAuth2AuthorizationCodeDetails( - testdata.accessTokenUrl, - testdata.clientID, - testdata.clientSecret, - testdata.oauth2Scopes, - ); - - // since we are moving to different, it will show unsaved changes dialog - // save datasource and then proceed - _.dataSources.SaveDatasource(); - - _.entityExplorer.SelectEntityByName("TestOAuth", "Queries/JS"); - _.agHelper.ActionContextMenuWithInPane("Delete", "Are you sure?"); - }); - - it("3. Create an API with app url and save as Datasource for Authorization code details test", function () { - _.apiPage.CreateAndFillApi(testdata.appUrl, "TestOAuth"); - _.agHelper.GetNClick(_.apiPage._saveAsDS); - // agHelper.ValidateToastMessage("datasource created"); //verifying there is no error toast, Bug 14566 - }); - - it("4. Add Oauth details to datasource and save", function () { - cy.get(datasource.saveBtn).should("not.be.disabled"); - _.dataSources.AddOAuth2AuthorizationCodeDetails( - testdata.accessTokenUrl, - testdata.clientID, - testdata.clientSecret, - testdata.authorizationURL, - ); - }); - - it("5. Validate save and Authorise", function () { - cy.get(datasource.saveAndAuthorize).click(); - cy.contains("#login-submit", "Login"); - cy.url().should("include", "oauth.mocklab.io/oauth/authorize"); - cy.xpath('//input[@name="email"]').type("Test@email.com"); - cy.xpath('//input[@name="email"]').type("Test"); - cy.xpath("//input[@name='password']").type("Test@123"); - cy.xpath("//input[@id='login-submit']").click(); - }); -}); diff --git a/app/client/cypress/e2e/Sanity/Datasources/RestApiOAuth2Validation_spec.ts b/app/client/cypress/e2e/Sanity/Datasources/RestApiOAuth2Validation_spec.ts index eba1ab5a80..cf7a1e01c8 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/RestApiOAuth2Validation_spec.ts +++ b/app/client/cypress/e2e/Sanity/Datasources/RestApiOAuth2Validation_spec.ts @@ -10,7 +10,8 @@ import { describe("Datasource form OAuth2 client credentials related tests", function () { let clientId, clientSecret; - it("1. Create an API with app url and save as Datasource for Client Credentials test", function () { + + it("1. Create an API with app url and save as Datasource for Authorization code details test", function () { dataSources.CreateOAuthClient("authorization_code"); apiPage.CreateAndFillApi( dataManager.dsValues[dataManager.defaultEnviorment].OAuth_ApiUrl + @@ -18,8 +19,7 @@ describe("Datasource form OAuth2 client credentials related tests", function () "TestOAuth", ); agHelper.GetNClick(apiPage._saveAsDS); - - // Add Oauth details to datasource and save + //Add Oauth details to datasource and save agHelper.AssertElementEnabledDisabled(dataSources._saveDs, 0, false); cy.get("@OAuthClientID").then((id) => { cy.get("@OAuthClientSecret").then((secret) => { @@ -30,40 +30,14 @@ describe("Datasource form OAuth2 client credentials related tests", function () .OAUth_AccessTokenUrl, clientId, clientSecret, - "profile", + dataManager.dsValues[dataManager.defaultEnviorment].OAuth_AuthUrl, ); }); }); - // since we are moving to different, it will show unsaved changes dialog - // save datasource and then proceed - dataSources.SaveDatasource(); - agHelper.ValidateToastMessage("datasource created"); //verifying there is no error toast, Bug 14566 - entityExplorer.SelectEntityByName("TestOAuth", "Queries/JS"); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.Api, - }); }); - it("2. Create an API with app url and save as Datasource for Authorization code details test", function () { - apiPage.CreateAndFillApi( - dataManager.dsValues[dataManager.defaultEnviorment].OAuth_ApiUrl + - "/api/echo/get?ASDSA=ASDSA", - "TestOAuth", - ); - agHelper.GetNClick(apiPage._saveAsDS); - //Add Oauth details to datasource and save - agHelper.AssertElementEnabledDisabled(dataSources._saveDs, 0, false); - dataSources.AddOAuth2AuthorizationCodeDetails( - dataManager.dsValues[dataManager.defaultEnviorment].OAUth_AccessTokenUrl, - clientId, - clientSecret, - dataManager.dsValues[dataManager.defaultEnviorment].OAuth_AuthUrl, - ); - }); - - it("3. Validate save and Authorise", function () { - agHelper.GetNClick(dataSources._saveAndAuthorizeDS); + it("2. Validate save and Authorise", function () { + agHelper.GetNClick(dataSources._saveDs); //Accept consent agHelper.GetNClick(dataSources._consent); diff --git a/app/client/cypress/e2e/Sanity/Datasources/SMTPDatasource_spec.js b/app/client/cypress/e2e/Sanity/Datasources/SMTPDatasource_spec.js index 3f7073d800..d1f076ea22 100644 --- a/app/client/cypress/e2e/Sanity/Datasources/SMTPDatasource_spec.js +++ b/app/client/cypress/e2e/Sanity/Datasources/SMTPDatasource_spec.js @@ -1,7 +1,6 @@ const datasource = require("../../../locators/DatasourcesEditor.json"); const queryLocators = require("../../../locators/QueryEditor.json"); import { agHelper } from "../../../support/Objects/ObjectsCore"; -let datasourceName; describe("SMTP datasource test cases using ted", function () { let SMTPDatasourceName; @@ -45,7 +44,7 @@ describe("SMTP datasource test cases using ted", function () { .type("{{Body.text}}", { parseSpecialCharSequences: false }); cy.get(queryLocators.queryFromEmail) .eq(6) - .type("{{FilePicker.text}}", { parseSpecialCharSequences: false }); + .type("{{FilePicker.files}}", { parseSpecialCharSequences: false }); cy.get(`.t--entity-name:contains("Page1")`) .should("be.visible") .click({ force: true }); @@ -54,27 +53,39 @@ describe("SMTP datasource test cases using ted", function () { it("2. On canvas, passing wrong email address in widgets should give error", function () { // verify an error is thrown when recipient address is not added - cy.xpath("//input[@class='bp3-input']").eq(0).type("test@appsmith.com"); - cy.get("span.bp3-button-text:contains('Run query')").closest("div").click(); + cy.xpath("//input[@class='bp3-input']") + .eq(0) + .type("test@appsmith.com") + .wait(500); + cy.get("span.bp3-button-text:contains('Run query')") + .closest("div") + .click() + .wait(500); cy.wait("@postExecute").then(({ response }) => { expect(response.body.data.statusCode).to.eq("PE-ARG-5000"); - expect(response.body.data.body).to.contain( - "Couldn't find a valid recipient address. Please check your action configuration", - ); }); + agHelper.WaitUntilToastDisappear( + "Couldn't find a valid recipient address. Please check your action configuration", + ); // verify an error is thrown when sender address is not added - cy.xpath("//input[@class='bp3-input']").eq(0).clear(); - cy.xpath("//input[@class='bp3-input']").eq(1).type("qwerty@appsmith.com"); - cy.get("span.bp3-button-text:contains('Run query')").closest("div").click(); + cy.xpath("//input[@class='bp3-input']").eq(0).clear().wait(500); + cy.xpath("//input[@class='bp3-input']") + .eq(1) + .type("qwerty@appsmith.com") + .wait(500); + cy.get("span.bp3-button-text:contains('Run query')") + .closest("div") + .click() + .wait(500); cy.wait("@postExecute").then(({ response }) => { expect(response.body.data.statusCode).to.eq("PE-ARG-5000"); - expect(response.body.data.body).to.contain( - "Couldn't find a valid sender address. Please check your action configuration", - ); }); + agHelper.ValidateToastMessage( + "Couldn't find a valid sender address. Please check your action configuration", + ); }); - /* it("3. On canvas, fill to email, from email, subject, body, attachment and run query", function() { + it("3. On canvas, fill to email, from email, subject, body, attachment and run query", function () { cy.get(`.t--entity-name:contains("smtpquery")`) .should("be.visible") .click({ force: true }); @@ -82,30 +93,33 @@ describe("SMTP datasource test cases using ted", function () { .should("be.visible") .click({ force: true }); cy.wait(2000); - cy.xpath("//input[@class='bp3-input']") - .eq(0) - .type("test@appsmith.com"); - cy.xpath("//input[@class='bp3-input']") - .eq(2) - .type("this is a smtp test"); + cy.xpath("//input[@class='bp3-input']").eq(0).type("test@appsmith.com"); + cy.xpath("//input[@class='bp3-input']").eq(2).type("this is a smtp test"); // adding an attachment in file picker - /* cy.SearchEntityandOpen("FilePicker"); const fixturePath = "testFile.mov"; - cy.get(commonlocators.filePickerButton).click(); - cy.get(commonlocators.filePickerInput) - .first() - .attachFile(fixturePath); - cy.get(commonlocators.filePickerUploadButton).click(); - cy.get(".bp3-spinner").should("have.length", 1); + agHelper.ClickButton("Select Files"); //1 files selected + agHelper.UploadFile(fixturePath); //eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(500); cy.get("button").contains("1 files selected"); - cy.xpath( - "//span[text()='Run query' and @class='bp3-button-text']", - ).click(); - cy.wait("@postExecute", { timeout: 8000 }).then(({ response }) => { - // expect(response.body.data.statusCode).to.eq("5000"); - expect(response.body.data.body).to.contain("Sent the email successfully"); + agHelper.ClickButton("Run query"); + agHelper.ValidateToastMessage("Sent the email successfully"); + + //Verifying if mail is sent/received using ted + const tedUrl = "http://localhost:5001/v1/cmd"; + cy.request({ + method: "GET", + url: tedUrl, + qs: { + cmd: "exim -bp", + }, + }).then((res) => { + expect(res.status).equal(200); + const responseBody = JSON.stringify(res.body); + cy.log(responseBody); + const containsTestAppsmith = /test@appsmith\.com/.test(responseBody); + const containsQwertyAppsmith = /qwerty@appsmith\.com/.test(responseBody); + expect(containsTestAppsmith || containsQwertyAppsmith).to.be.true; }); - }); */ + }); }); diff --git a/app/client/cypress/e2e/Smoke/Apps/ReconnectDatasource_spec.js b/app/client/cypress/e2e/Smoke/Apps/ReconnectDatasource_spec.js index 1de44d21d1..0ee6113677 100644 --- a/app/client/cypress/e2e/Smoke/Apps/ReconnectDatasource_spec.js +++ b/app/client/cypress/e2e/Smoke/Apps/ReconnectDatasource_spec.js @@ -12,7 +12,6 @@ describe("Reconnect Datasource Modal validation while importing application", fu // import application cy.generateUUID().then((uid) => { workspaceId = uid; - localStorage.setItem("WorkspaceName", workspaceId); cy.createWorkspace(); cy.wait("@createWorkspace").then((createWorkspaceInterception) => { newWorkspaceName = createWorkspaceInterception.response.body.data.name; diff --git a/app/client/cypress/fixtures/Appsmith.gif b/app/client/cypress/fixtures/Appsmith.gif new file mode 100644 index 0000000000..53c281cd21 Binary files /dev/null and b/app/client/cypress/fixtures/Appsmith.gif differ diff --git a/app/client/cypress/fixtures/ContainerWithOtherWidgetsDsl.json b/app/client/cypress/fixtures/ContainerWithOtherWidgetsDsl.json new file mode 100644 index 0000000000..52cf3c13be --- /dev/null +++ b/app/client/cypress/fixtures/ContainerWithOtherWidgetsDsl.json @@ -0,0 +1,779 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 720, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 17, + "widgetName": "Container1", + "borderColor": "#E0DEDE", + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": [ + "div", + "parent", + "group" + ], + "topRow": 7, + "bottomRow": 51, + "parentRowSpace": 10, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 42, + "animateLoading": true, + "parentColumnSpace": 6.15625, + "leftColumn": 11, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 100, + "widgetName": "Canvas1", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 440, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "minHeight": 100, + "mobileRightColumn": 147.75, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 2, + "pageSize": 3, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8, + "animateLoading": true, + "dynamicBindingPathList": [ + { + "key": "currentItemsView" + }, + { + "key": "selectedItemView" + }, + { + "key": "triggeredItemView" + }, + { + "key": "primaryKeys" + }, + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "leftColumn": 7, + "enhancements": true, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 400, + "widgetName": "Canvas2", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 400, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400, + "mobileRightColumn": 47.90625, + "noPad": true, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12, + "widgetName": "Container2", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": [ + "div", + "parent", + "group" + ], + "topRow": 0, + "bottomRow": 12, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64, + "animateLoading": true, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "widgetName": "Canvas3", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 120, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Image1", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0, + "bottomRow": 8, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { + "key": "image" + }, + { + "key": "borderRadius" + } + ], + "leftColumn": 0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "5o3alick0b", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 16, + "objectFit": "cover", + "widgetId": "r0irnnqyer", + "isVisible": true, + "version": 1, + "parentId": "3eg2i7cvb7", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "maxZoomLevel": 1, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0, + "bottomRow": 4, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "5ejbjgp4n5", + "isDeprecated": false, + "rightColumn": 28, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "q34mntnwo8", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "3eg2i7cvb7", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4, + "bottomRow": 8, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "5ejbjgp4n5", + "isDeprecated": false, + "rightColumn": 24, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "xihj8ujve1", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "3eg2i7cvb7", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4 + } + ], + "key": "0g64f23mqn", + "isDeprecated": false, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "3eg2i7cvb7", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "vp4sn8j5m8", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 4, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "73k67128ed", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64, + "dynamicHeight": "FIXED", + "widgetId": "vp4sn8j5m8", + "containerStyle": "card", + "minWidth": 450, + "isVisible": true, + "version": 1, + "isListItemContainer": true, + "parentId": "gde9r8gkvh", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": [ + "dynamicHeight" + ], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 10 + } + ], + "key": "0g64f23mqn", + "isDeprecated": false, + "rightColumn": 47.90625, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "gde9r8gkvh", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "02o8nwg9kr", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 4, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": [ + "Suggested", + "Display" + ], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "gde9r8gkvh", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 42, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List1", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 42, + "parentRowSpace": 10, + "hideCard": false, + "templateBottomRow": 16, + "mobileRightColumn": 40, + "mainContainerId": "vp4sn8j5m8", + "primaryKeys": "{{List1.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 1.99609375, + "gridType": "vertical", + "key": "w2a97fitgw", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 61, + "widgetId": "02o8nwg9kr", + "minWidth": 450, + "parentId": "gbz159zvqu", + "renderMode": "CANVAS", + "mobileTopRow": 2, + "responsiveBehavior": "fill", + "mobileLeftColumn": 16, + "selectedItemView": "{{{}}}" + } + ], + "key": "0g64f23mqn", + "isDeprecated": false, + "rightColumn": 147.75, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "gbz159zvqu", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "jpinylysln", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 4, + "flexLayers": [] + } + ], + "borderWidth": "1", + "flexVerticalAlignment": "start", + "key": "73k67128ed", + "backgroundColor": "#FFFFFF", + "isDeprecated": false, + "rightColumn": 55, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "jpinylysln", + "containerStyle": "card", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "0", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 7, + "responsiveBehavior": "fill", + "originalTopRow": 7, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 18, + "maxDynamicHeight": 9000, + "originalBottomRow": 51, + "minDynamicHeight": 10 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.f2c34197dbcf03595098986de898928f.svg", + "topRow": 57, + "labelWidth": 5, + "type": "INPUT_WIDGET_V2", + "animateLoading": true, + "resetOnSubmit": true, + "leftColumn": 6, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + } + ], + "labelStyle": "", + "inputType": "TEXT", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": false, + "isVisible": true, + "version": 2, + "tags": [ + "Suggested", + "Inputs" + ], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 64, + "mobileBottomRow": 64, + "widgetName": "Input1", + "displayName": "Input", + "searchTags": [ + "form", + "text input", + "number", + "textarea" + ], + "bottomRow": 64, + "parentRowSpace": 10, + "autoFocus": false, + "hideCard": false, + "mobileRightColumn": 26, + "parentColumnSpace": 6.15625, + "labelPosition": "Top", + "key": "4mdmu15irm", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 26, + "widgetId": "yxw17vhw6c", + "minWidth": 450, + "label": "Label", + "parentId": "0", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 57, + "responsiveBehavior": "fill", + "originalTopRow": 57, + "mobileLeftColumn": 6, + "maxDynamicHeight": 9000, + "iconAlign": "left", + "defaultText": "", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.a7b19dc8b31d68fcff57f1d2c0084a18.svg", + "labelText": "Label", + "topRow": 57, + "labelWidth": 5, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "defaultOptionValue": "GREEN", + "animateLoading": true, + "leftColumn": 36, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + } + ], + "placeholderText": "Select option", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1, + "tags": [ + "Suggested", + "Select" + ], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 64, + "mobileBottomRow": 64, + "widgetName": "Select1", + "isFilterable": true, + "displayName": "Select", + "searchTags": [ + "dropdown" + ], + "bottomRow": 64, + "parentRowSpace": 10, + "hideCard": false, + "mobileRightColumn": 56, + "parentColumnSpace": 6.15625, + "labelPosition": "Top", + "sourceData": [ + { + "name": "Blue", + "code": "BLUE" + }, + { + "name": "Green", + "code": "GREEN" + }, + { + "name": "Red", + "code": "RED" + } + ], + "key": "9maq3hjt2n", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 56, + "widgetId": "28n5cju0he", + "optionValue": "code", + "minWidth": 450, + "parentId": "0", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 57, + "optionLabel": "name", + "responsiveBehavior": "fill", + "originalTopRow": 57, + "mobileLeftColumn": 36, + "maxDynamicHeight": 9000, + "minDynamicHeight": 4 + }, + { + "mobileBottomRow": 72, + "widgetName": "Text3", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 68, + "bottomRow": 72, + "parentRowSpace": 10, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 38, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 6.15625, + "leftColumn": 22, + "dynamicBindingPathList": [ + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Hello {{appsmith.user.name || appsmith.user.email}}", + "key": "5ejbjgp4n5", + "isDeprecated": false, + "rightColumn": 38, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "qql0hbrzwv", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "0", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 68, + "responsiveBehavior": "fill", + "originalTopRow": 68, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 22, + "maxDynamicHeight": 9000, + "originalBottomRow": 72, + "fontSize": "1rem", + "minDynamicHeight": 4 + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/fixtures/ImportAppAllAccess.json b/app/client/cypress/fixtures/ImportAppAllAccess.json new file mode 100644 index 0000000000..c894182e4a --- /dev/null +++ b/app/client/cypress/fixtures/ImportAppAllAccess.json @@ -0,0 +1 @@ +{"clientSchemaVersion":1.0,"serverSchemaVersion":6.0,"exportedApplication":{"name":"ImportAppAllAccess","isPublic":false,"pages":[{"id":"Page1","isDefault":true}],"publishedPages":[{"id":"Page1","isDefault":true}],"viewMode":false,"appIsExample":false,"unreadCommentThreads":0.0,"color":"#CCCCCC","icon":"call","slug":"importappallaccess","unpublishedCustomJSLibs":[],"publishedCustomJSLibs":[],"evaluationVersion":2.0,"applicationVersion":2.0,"collapseInvisibleWidgets":true,"isManualUpdate":false,"deleted":false},"datasourceList":[{"name":"gsheet","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"deleted":false,"gitSyncId":"6507db87f847163dfe7777c4_6507dbd7f847163dfe7777cd"}],"customJSLibList":[],"pageList":[{"unpublishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":4896.0,"snapColumns":64.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":380.0,"containerStyle":"none","snapRows":124.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":86.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[{"boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","borderColor":"#E0DEDE","isVisibleDownload":true,"iconSVG":"/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg","topRow":0.0,"isSortable":true,"type":"TABLE_WIDGET_V2","inlineEditingSaveOption":"ROW_LEVEL","animateLoading":true,"dynamicBindingPathList":[{"key":"accentColor"},{"key":"borderRadius"},{"key":"boxShadow"},{"key":"tableData"},{"key":"primaryColumns.uniq_id.computedValue"},{"key":"primaryColumns.japanese_name.computedValue"},{"key":"primaryColumns.currencies.computedValue"},{"key":"primaryColumns.specialChars.computedValue"},{"key":"primaryColumns.product_name.computedValue"},{"key":"primaryColumns.manufacturer.computedValue"},{"key":"primaryColumns.price.computedValue"},{"key":"primaryColumns.number_available_in_stock.computedValue"},{"key":"primaryColumns.number_of_reviews.computedValue"},{"key":"primaryColumns.number_of_answered_questions.computedValue"},{"key":"primaryColumns.average_review_rating.computedValue"},{"key":"primaryColumns.amazon_category_and_sub_category.computedValue"},{"key":"primaryColumns.customers_who_bought_this_item_also_bought.computedValue"},{"key":"primaryColumns.rowIndex.computedValue"}],"needsHeightForContent":true,"leftColumn":0.0,"delimiter":",","defaultSelectedRowIndex":0.0,"accentColor":"{{appsmith.theme.colors.primaryColor}}","isVisibleFilters":true,"isVisible":true,"enableClientSideSearch":true,"version":2.0,"totalRecordsCount":0.0,"tags":["Suggested","Display"],"isLoading":false,"childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","columnUpdatedAt":1.695963199756E12,"defaultSelectedRowIndices":[0.0],"mobileBottomRow":29.0,"widgetName":"Table1","defaultPageSize":0.0,"columnOrder":["uniq_id","japanese_name","currencies","specialChars","product_name","manufacturer","price","number_available_in_stock","number_of_reviews","number_of_answered_questions","average_review_rating","amazon_category_and_sub_category","customers_who_bought_this_item_also_bought","rowIndex"],"dynamicPropertyPathList":[],"displayName":"Table","bottomRow":28.0,"columnWidthMap":{},"parentRowSpace":10.0,"hideCard":false,"mobileRightColumn":34.0,"parentColumnSpace":16.65625,"dynamicTriggerPathList":[],"borderWidth":"1","primaryColumns":{"uniq_id":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":0.0,"width":150.0,"originalId":"uniq_id","id":"uniq_id","alias":"uniq_id","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"uniq_id","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"uniq_id\"]))}}","sticky":"","validation":{}},"japanese_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":1.0,"width":150.0,"originalId":"japanese_name","id":"japanese_name","alias":"japanese_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"japanese_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"japanese_name\"]))}}","sticky":"","validation":{}},"currencies":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":2.0,"width":150.0,"originalId":"currencies","id":"currencies","alias":"currencies","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"currencies","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"currencies\"]))}}","sticky":"","validation":{}},"specialChars":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":3.0,"width":150.0,"originalId":"specialChars","id":"specialChars","alias":"specialChars","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"specialChars","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"specialChars\"]))}}","sticky":"","validation":{}},"product_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":4.0,"width":150.0,"originalId":"product_name","id":"product_name","alias":"product_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"product_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"product_name\"]))}}","sticky":"","validation":{}},"manufacturer":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":5.0,"width":150.0,"originalId":"manufacturer","id":"manufacturer","alias":"manufacturer","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"manufacturer","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"manufacturer\"]))}}","sticky":"","validation":{}},"price":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":6.0,"width":150.0,"originalId":"price","id":"price","alias":"price","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"price","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"price\"]))}}","sticky":"","validation":{}},"number_available_in_stock":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":7.0,"width":150.0,"originalId":"number_available_in_stock","id":"number_available_in_stock","alias":"number_available_in_stock","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_available_in_stock","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_available_in_stock\"]))}}","sticky":"","validation":{}},"number_of_reviews":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":8.0,"width":150.0,"originalId":"number_of_reviews","id":"number_of_reviews","alias":"number_of_reviews","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_reviews","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_reviews\"]))}}","sticky":"","validation":{}},"number_of_answered_questions":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":9.0,"width":150.0,"originalId":"number_of_answered_questions","id":"number_of_answered_questions","alias":"number_of_answered_questions","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_answered_questions","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_answered_questions\"]))}}","sticky":"","validation":{}},"average_review_rating":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":10.0,"width":150.0,"originalId":"average_review_rating","id":"average_review_rating","alias":"average_review_rating","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"average_review_rating","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"average_review_rating\"]))}}","sticky":"","validation":{}},"amazon_category_and_sub_category":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":11.0,"width":150.0,"originalId":"amazon_category_and_sub_category","id":"amazon_category_and_sub_category","alias":"amazon_category_and_sub_category","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"amazon_category_and_sub_category","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"amazon_category_and_sub_category\"]))}}","sticky":"","validation":{}},"customers_who_bought_this_item_also_bought":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":12.0,"width":150.0,"originalId":"customers_who_bought_this_item_also_bought","id":"customers_who_bought_this_item_also_bought","alias":"customers_who_bought_this_item_also_bought","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"customers_who_bought_this_item_also_bought","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"customers_who_bought_this_item_also_bought\"]))}}","sticky":"","validation":{}},"rowIndex":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":13.0,"width":150.0,"originalId":"rowIndex","id":"rowIndex","alias":"rowIndex","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"rowIndex","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"rowIndex\"]))}}","sticky":"","validation":{}}},"key":"y3e8fye419","canFreezeColumn":true,"isDeprecated":false,"rightColumn":34.0,"textSize":"0.875rem","widgetId":"5w278g8zo9","minWidth":450.0,"tableData":"{{fetch_many_query.data}}","label":"Data","searchKey":"","parentId":"0","renderMode":"CANVAS","mobileTopRow":1.0,"horizontalAlignment":"LEFT","isVisibleSearch":true,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"isVisiblePagination":true,"verticalAlignment":"CENTER"}]},"layoutOnLoadActions":[[{"id":"Page1_fetch_many_query","name":"fetch_many_query","confirmBeforeExecute":false,"pluginType":"SAAS","jsonPathKeys":[],"timeoutInMillisecond":10000.0}]],"layoutOnLoadActionErrors":[],"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"publishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":1224.0,"snapColumns":16.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":1250.0,"containerStyle":"none","snapRows":33.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":4.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[]},"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f37b43d9217d781a526"}],"actionList":[{"pluginType":"SAAS","pluginId":"google-sheets-plugin","unpublishedAction":{"name":"fetch_many_query","datasource":{"name":"gsheet","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"id":"gsheet","deleted":false,"policies":[],"userPermissions":[]},"pageId":"Page1","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","encodeParamsToggle":true,"selfReferencingDataPaths":[],"formData":{"command":{"data":"FETCH_MANY"},"entityType":{"data":"ROWS"},"tableHeaderIndex":{"data":"1"},"projection":{"data":[]},"queryFormat":{"data":"ROWS"},"range":{"data":""},"where":{"data":{"condition":"AND","children":[{"condition":"LT"}]}},"pagination":{"data":{"limit":"20","offset":"0"}},"smartSubstitution":{"data":true},"sheetUrl":{"data":"https://docs.google.com/spreadsheets/d/1rD1Bo4x-y9B7EqaVs8HuJViGSEVBeiLPuTdxMoC2uDw/edit"},"sheetName":{"data":"Sheet1"},"sortBy":{"data":[{"column":"","order":"Ascending"}]}}},"executeOnLoad":true,"dynamicBindingPathList":[],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-29T04:15:25Z"},"publishedAction":{"datasource":{"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"messages":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[]},"id":"Page1_fetch_many_query","deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f5db43d9217d781a52b"}],"actionCollectionList":[],"updatedResources":{"customJSLibList":[],"actionList":["fetch_many_query##ENTITY_SEPARATOR##Page1"],"pageList":["Page1"],"actionCollectionList":[]},"editModeTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false},"publishedTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false}} \ No newline at end of file diff --git a/app/client/cypress/fixtures/ImportAppReadAccess.json b/app/client/cypress/fixtures/ImportAppReadAccess.json new file mode 100644 index 0000000000..d26323d4e0 --- /dev/null +++ b/app/client/cypress/fixtures/ImportAppReadAccess.json @@ -0,0 +1 @@ +{"clientSchemaVersion":1.0,"serverSchemaVersion":6.0,"exportedApplication":{"name":"ImportAppReadAccess","isPublic":false,"pages":[{"id":"Page1","isDefault":true}],"publishedPages":[{"id":"Page1","isDefault":true}],"viewMode":false,"appIsExample":false,"unreadCommentThreads":0.0,"color":"#CCCCCC","icon":"call","slug":"importappreadaccess","unpublishedCustomJSLibs":[],"publishedCustomJSLibs":[],"evaluationVersion":2.0,"applicationVersion":2.0,"collapseInvisibleWidgets":true,"isManualUpdate":false,"deleted":false},"datasourceList":[{"name":"gsheet-read","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"deleted":false,"gitSyncId":"6507db87f847163dfe7777c4_6507dc86f847163dfe7777d5"}],"customJSLibList":[],"pageList":[{"unpublishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":4896.0,"snapColumns":64.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":380.0,"containerStyle":"none","snapRows":124.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":86.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[{"boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","borderColor":"#E0DEDE","isVisibleDownload":true,"iconSVG":"/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg","topRow":0.0,"isSortable":true,"type":"TABLE_WIDGET_V2","inlineEditingSaveOption":"ROW_LEVEL","animateLoading":true,"dynamicBindingPathList":[{"key":"accentColor"},{"key":"borderRadius"},{"key":"boxShadow"},{"key":"tableData"},{"key":"primaryColumns.uniq_id.computedValue"},{"key":"primaryColumns.japanese_name.computedValue"},{"key":"primaryColumns.currencies.computedValue"},{"key":"primaryColumns.specialChars.computedValue"},{"key":"primaryColumns.product_name.computedValue"},{"key":"primaryColumns.manufacturer.computedValue"},{"key":"primaryColumns.price.computedValue"},{"key":"primaryColumns.number_available_in_stock.computedValue"},{"key":"primaryColumns.number_of_reviews.computedValue"},{"key":"primaryColumns.number_of_answered_questions.computedValue"},{"key":"primaryColumns.average_review_rating.computedValue"},{"key":"primaryColumns.amazon_category_and_sub_category.computedValue"},{"key":"primaryColumns.customers_who_bought_this_item_also_bought.computedValue"},{"key":"primaryColumns.rowIndex.computedValue"}],"needsHeightForContent":true,"leftColumn":0.0,"delimiter":",","defaultSelectedRowIndex":0.0,"accentColor":"{{appsmith.theme.colors.primaryColor}}","isVisibleFilters":true,"isVisible":true,"enableClientSideSearch":true,"version":2.0,"totalRecordsCount":0.0,"tags":["Suggested","Display"],"isLoading":false,"childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","columnUpdatedAt":1.695963199756E12,"defaultSelectedRowIndices":[0.0],"mobileBottomRow":29.0,"widgetName":"Table1","defaultPageSize":0.0,"columnOrder":["uniq_id","japanese_name","currencies","specialChars","product_name","manufacturer","price","number_available_in_stock","number_of_reviews","number_of_answered_questions","average_review_rating","amazon_category_and_sub_category","customers_who_bought_this_item_also_bought","rowIndex"],"dynamicPropertyPathList":[],"displayName":"Table","bottomRow":28.0,"columnWidthMap":{},"parentRowSpace":10.0,"hideCard":false,"mobileRightColumn":34.0,"parentColumnSpace":16.65625,"dynamicTriggerPathList":[],"borderWidth":"1","primaryColumns":{"uniq_id":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":0.0,"width":150.0,"originalId":"uniq_id","id":"uniq_id","alias":"uniq_id","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"uniq_id","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"uniq_id\"]))}}","sticky":"","validation":{}},"japanese_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":1.0,"width":150.0,"originalId":"japanese_name","id":"japanese_name","alias":"japanese_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"japanese_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"japanese_name\"]))}}","sticky":"","validation":{}},"currencies":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":2.0,"width":150.0,"originalId":"currencies","id":"currencies","alias":"currencies","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"currencies","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"currencies\"]))}}","sticky":"","validation":{}},"specialChars":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":3.0,"width":150.0,"originalId":"specialChars","id":"specialChars","alias":"specialChars","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"specialChars","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"specialChars\"]))}}","sticky":"","validation":{}},"product_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":4.0,"width":150.0,"originalId":"product_name","id":"product_name","alias":"product_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"product_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"product_name\"]))}}","sticky":"","validation":{}},"manufacturer":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":5.0,"width":150.0,"originalId":"manufacturer","id":"manufacturer","alias":"manufacturer","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"manufacturer","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"manufacturer\"]))}}","sticky":"","validation":{}},"price":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":6.0,"width":150.0,"originalId":"price","id":"price","alias":"price","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"price","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"price\"]))}}","sticky":"","validation":{}},"number_available_in_stock":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":7.0,"width":150.0,"originalId":"number_available_in_stock","id":"number_available_in_stock","alias":"number_available_in_stock","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_available_in_stock","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_available_in_stock\"]))}}","sticky":"","validation":{}},"number_of_reviews":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":8.0,"width":150.0,"originalId":"number_of_reviews","id":"number_of_reviews","alias":"number_of_reviews","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_reviews","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_reviews\"]))}}","sticky":"","validation":{}},"number_of_answered_questions":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":9.0,"width":150.0,"originalId":"number_of_answered_questions","id":"number_of_answered_questions","alias":"number_of_answered_questions","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_answered_questions","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_answered_questions\"]))}}","sticky":"","validation":{}},"average_review_rating":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":10.0,"width":150.0,"originalId":"average_review_rating","id":"average_review_rating","alias":"average_review_rating","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"average_review_rating","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"average_review_rating\"]))}}","sticky":"","validation":{}},"amazon_category_and_sub_category":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":11.0,"width":150.0,"originalId":"amazon_category_and_sub_category","id":"amazon_category_and_sub_category","alias":"amazon_category_and_sub_category","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"amazon_category_and_sub_category","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"amazon_category_and_sub_category\"]))}}","sticky":"","validation":{}},"customers_who_bought_this_item_also_bought":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":12.0,"width":150.0,"originalId":"customers_who_bought_this_item_also_bought","id":"customers_who_bought_this_item_also_bought","alias":"customers_who_bought_this_item_also_bought","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"customers_who_bought_this_item_also_bought","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"customers_who_bought_this_item_also_bought\"]))}}","sticky":"","validation":{}},"rowIndex":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":13.0,"width":150.0,"originalId":"rowIndex","id":"rowIndex","alias":"rowIndex","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"rowIndex","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"rowIndex\"]))}}","sticky":"","validation":{}}},"key":"y3e8fye419","canFreezeColumn":true,"isDeprecated":false,"rightColumn":34.0,"textSize":"0.875rem","widgetId":"5w278g8zo9","minWidth":450.0,"tableData":"{{fetch_many_query_read_only.data}}","label":"Data","searchKey":"","parentId":"0","renderMode":"CANVAS","mobileTopRow":1.0,"horizontalAlignment":"LEFT","isVisibleSearch":true,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"isVisiblePagination":true,"verticalAlignment":"CENTER"}]},"layoutOnLoadActions":[[{"id":"Page1_fetch_many_query_read_only","name":"fetch_many_query_read_only","confirmBeforeExecute":false,"pluginType":"SAAS","jsonPathKeys":[],"timeoutInMillisecond":10000.0}]],"layoutOnLoadActionErrors":[],"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"publishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":1224.0,"snapColumns":16.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":1250.0,"containerStyle":"none","snapRows":33.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":4.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[]},"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f37b43d9217d781a526"}],"actionList":[{"pluginType":"SAAS","pluginId":"google-sheets-plugin","unpublishedAction":{"name":"fetch_many_query_read_only","datasource":{"name":"gsheet-read","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"id":"gsheet-read","deleted":false,"policies":[],"userPermissions":[]},"pageId":"Page1","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","encodeParamsToggle":true,"selfReferencingDataPaths":[],"formData":{"command":{"data":"FETCH_MANY"},"entityType":{"data":"ROWS"},"tableHeaderIndex":{"data":"1"},"projection":{"data":[]},"queryFormat":{"data":"ROWS"},"range":{"data":""},"where":{"data":{"condition":"AND","children":[{"condition":"LT"}]}},"pagination":{"data":{"limit":"20","offset":"0"}},"smartSubstitution":{"data":true},"sheetUrl":{"data":"https://docs.google.com/spreadsheets/d/1rD1Bo4x-y9B7EqaVs8HuJViGSEVBeiLPuTdxMoC2uDw/edit"},"sheetName":{"data":"Sheet1"},"sortBy":{"data":[{"column":"","order":"Ascending"}]}}},"executeOnLoad":true,"dynamicBindingPathList":[],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-29T04:53:53Z"},"publishedAction":{"datasource":{"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"messages":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[]},"id":"Page1_fetch_many_query_read_only","deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f5db43d9217d781a52b"}],"actionCollectionList":[],"updatedResources":{"customJSLibList":[],"actionList":["fetch_many_query_read_only##ENTITY_SEPARATOR##Page1"],"pageList":["Page1"],"actionCollectionList":[]},"editModeTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false},"publishedTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false}} \ No newline at end of file diff --git a/app/client/cypress/fixtures/ImportAppReadWriteAccess.json b/app/client/cypress/fixtures/ImportAppReadWriteAccess.json new file mode 100644 index 0000000000..c30151c01a --- /dev/null +++ b/app/client/cypress/fixtures/ImportAppReadWriteAccess.json @@ -0,0 +1 @@ +{"clientSchemaVersion":1.0,"serverSchemaVersion":6.0,"exportedApplication":{"name":"ImportAppReadWriteAccess","isPublic":false,"pages":[{"id":"Page1","isDefault":true}],"publishedPages":[{"id":"Page1","isDefault":true}],"viewMode":false,"appIsExample":false,"unreadCommentThreads":0.0,"color":"#CCCCCC","icon":"call","slug":"importappreadwriteaccess","unpublishedCustomJSLibs":[],"publishedCustomJSLibs":[],"evaluationVersion":2.0,"applicationVersion":2.0,"collapseInvisibleWidgets":true,"isManualUpdate":false,"deleted":false},"datasourceList":[{"name":"gsheet-read-write","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"deleted":false,"gitSyncId":"6507db87f847163dfe7777c4_6507dcb0f847163dfe7777d9"}],"customJSLibList":[],"pageList":[{"unpublishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":4896.0,"snapColumns":64.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":380.0,"containerStyle":"none","snapRows":124.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":86.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[{"boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","borderColor":"#E0DEDE","isVisibleDownload":true,"iconSVG":"/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg","topRow":0.0,"isSortable":true,"type":"TABLE_WIDGET_V2","inlineEditingSaveOption":"ROW_LEVEL","animateLoading":true,"dynamicBindingPathList":[{"key":"accentColor"},{"key":"borderRadius"},{"key":"boxShadow"},{"key":"tableData"},{"key":"primaryColumns.uniq_id.computedValue"},{"key":"primaryColumns.japanese_name.computedValue"},{"key":"primaryColumns.currencies.computedValue"},{"key":"primaryColumns.specialChars.computedValue"},{"key":"primaryColumns.product_name.computedValue"},{"key":"primaryColumns.manufacturer.computedValue"},{"key":"primaryColumns.price.computedValue"},{"key":"primaryColumns.number_available_in_stock.computedValue"},{"key":"primaryColumns.number_of_reviews.computedValue"},{"key":"primaryColumns.number_of_answered_questions.computedValue"},{"key":"primaryColumns.average_review_rating.computedValue"},{"key":"primaryColumns.amazon_category_and_sub_category.computedValue"},{"key":"primaryColumns.customers_who_bought_this_item_also_bought.computedValue"},{"key":"primaryColumns.rowIndex.computedValue"}],"needsHeightForContent":true,"leftColumn":0.0,"delimiter":",","defaultSelectedRowIndex":0.0,"accentColor":"{{appsmith.theme.colors.primaryColor}}","isVisibleFilters":true,"isVisible":true,"enableClientSideSearch":true,"version":2.0,"totalRecordsCount":0.0,"tags":["Suggested","Display"],"isLoading":false,"childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","columnUpdatedAt":1.695963199756E12,"defaultSelectedRowIndices":[0.0],"mobileBottomRow":29.0,"widgetName":"Table1","defaultPageSize":0.0,"columnOrder":["uniq_id","japanese_name","currencies","specialChars","product_name","manufacturer","price","number_available_in_stock","number_of_reviews","number_of_answered_questions","average_review_rating","amazon_category_and_sub_category","customers_who_bought_this_item_also_bought","rowIndex"],"dynamicPropertyPathList":[],"displayName":"Table","bottomRow":28.0,"columnWidthMap":{},"parentRowSpace":10.0,"hideCard":false,"mobileRightColumn":34.0,"parentColumnSpace":16.65625,"dynamicTriggerPathList":[],"borderWidth":"1","primaryColumns":{"uniq_id":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":0.0,"width":150.0,"originalId":"uniq_id","id":"uniq_id","alias":"uniq_id","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"uniq_id","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"uniq_id\"]))}}","sticky":"","validation":{}},"japanese_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":1.0,"width":150.0,"originalId":"japanese_name","id":"japanese_name","alias":"japanese_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"japanese_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"japanese_name\"]))}}","sticky":"","validation":{}},"currencies":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":2.0,"width":150.0,"originalId":"currencies","id":"currencies","alias":"currencies","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"currencies","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"currencies\"]))}}","sticky":"","validation":{}},"specialChars":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":3.0,"width":150.0,"originalId":"specialChars","id":"specialChars","alias":"specialChars","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"specialChars","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"specialChars\"]))}}","sticky":"","validation":{}},"product_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":4.0,"width":150.0,"originalId":"product_name","id":"product_name","alias":"product_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"product_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"product_name\"]))}}","sticky":"","validation":{}},"manufacturer":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":5.0,"width":150.0,"originalId":"manufacturer","id":"manufacturer","alias":"manufacturer","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"manufacturer","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"manufacturer\"]))}}","sticky":"","validation":{}},"price":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":6.0,"width":150.0,"originalId":"price","id":"price","alias":"price","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"price","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"price\"]))}}","sticky":"","validation":{}},"number_available_in_stock":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":7.0,"width":150.0,"originalId":"number_available_in_stock","id":"number_available_in_stock","alias":"number_available_in_stock","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_available_in_stock","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_available_in_stock\"]))}}","sticky":"","validation":{}},"number_of_reviews":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":8.0,"width":150.0,"originalId":"number_of_reviews","id":"number_of_reviews","alias":"number_of_reviews","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_reviews","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_reviews\"]))}}","sticky":"","validation":{}},"number_of_answered_questions":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":9.0,"width":150.0,"originalId":"number_of_answered_questions","id":"number_of_answered_questions","alias":"number_of_answered_questions","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_answered_questions","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_answered_questions\"]))}}","sticky":"","validation":{}},"average_review_rating":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":10.0,"width":150.0,"originalId":"average_review_rating","id":"average_review_rating","alias":"average_review_rating","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"average_review_rating","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"average_review_rating\"]))}}","sticky":"","validation":{}},"amazon_category_and_sub_category":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":11.0,"width":150.0,"originalId":"amazon_category_and_sub_category","id":"amazon_category_and_sub_category","alias":"amazon_category_and_sub_category","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"amazon_category_and_sub_category","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"amazon_category_and_sub_category\"]))}}","sticky":"","validation":{}},"customers_who_bought_this_item_also_bought":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":12.0,"width":150.0,"originalId":"customers_who_bought_this_item_also_bought","id":"customers_who_bought_this_item_also_bought","alias":"customers_who_bought_this_item_also_bought","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"customers_who_bought_this_item_also_bought","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"customers_who_bought_this_item_also_bought\"]))}}","sticky":"","validation":{}},"rowIndex":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":13.0,"width":150.0,"originalId":"rowIndex","id":"rowIndex","alias":"rowIndex","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"rowIndex","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"rowIndex\"]))}}","sticky":"","validation":{}}},"key":"y3e8fye419","canFreezeColumn":true,"isDeprecated":false,"rightColumn":34.0,"textSize":"0.875rem","widgetId":"5w278g8zo9","minWidth":450.0,"tableData":"{{fetch_many_query_read_write.data}}","label":"Data","searchKey":"","parentId":"0","renderMode":"CANVAS","mobileTopRow":1.0,"horizontalAlignment":"LEFT","isVisibleSearch":true,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"isVisiblePagination":true,"verticalAlignment":"CENTER"}]},"layoutOnLoadActions":[[{"id":"Page1_fetch_many_query_read_write","name":"fetch_many_query_read_write","confirmBeforeExecute":false,"pluginType":"SAAS","jsonPathKeys":[],"timeoutInMillisecond":10000.0}]],"layoutOnLoadActionErrors":[],"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"publishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":1224.0,"snapColumns":16.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":1250.0,"containerStyle":"none","snapRows":33.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":4.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[]},"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f37b43d9217d781a526"}],"actionList":[{"pluginType":"SAAS","pluginId":"google-sheets-plugin","unpublishedAction":{"name":"fetch_many_query_read_write","datasource":{"name":"gsheet-read-write","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"id":"gsheet-read-write","deleted":false,"policies":[],"userPermissions":[]},"pageId":"Page1","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","encodeParamsToggle":true,"selfReferencingDataPaths":[],"formData":{"command":{"data":"FETCH_MANY"},"entityType":{"data":"ROWS"},"tableHeaderIndex":{"data":"1"},"projection":{"data":[]},"queryFormat":{"data":"ROWS"},"range":{"data":""},"where":{"data":{"condition":"AND","children":[{"condition":"LT"}]}},"pagination":{"data":{"limit":"20","offset":"0"}},"smartSubstitution":{"data":true},"sheetUrl":{"data":"https://docs.google.com/spreadsheets/d/1rD1Bo4x-y9B7EqaVs8HuJViGSEVBeiLPuTdxMoC2uDw/edit"},"sheetName":{"data":"Sheet1"},"sortBy":{"data":[{"column":"","order":"Ascending"}]}}},"executeOnLoad":true,"dynamicBindingPathList":[],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-29T04:56:32Z"},"publishedAction":{"datasource":{"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"messages":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[]},"id":"Page1_fetch_many_query_read_write","deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f5db43d9217d781a52b"}],"actionCollectionList":[],"updatedResources":{"customJSLibList":[],"actionList":["fetch_many_query_read_write##ENTITY_SEPARATOR##Page1"],"pageList":["Page1"],"actionCollectionList":[]},"editModeTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false},"publishedTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false}} \ No newline at end of file diff --git a/app/client/cypress/fixtures/ImportAppSelectedAccess.json b/app/client/cypress/fixtures/ImportAppSelectedAccess.json new file mode 100644 index 0000000000..8b2b6bdd0b --- /dev/null +++ b/app/client/cypress/fixtures/ImportAppSelectedAccess.json @@ -0,0 +1 @@ +{"clientSchemaVersion":1.0,"serverSchemaVersion":6.0,"exportedApplication":{"name":"ImportAppSelectedAccess","isPublic":false,"pages":[{"id":"Page1","isDefault":true}],"publishedPages":[{"id":"Page1","isDefault":true}],"viewMode":false,"appIsExample":false,"unreadCommentThreads":0.0,"color":"#CCCCCC","icon":"call","slug":"importappselectedaccess","unpublishedCustomJSLibs":[],"publishedCustomJSLibs":[],"evaluationVersion":2.0,"applicationVersion":2.0,"collapseInvisibleWidgets":true,"isManualUpdate":false,"deleted":false},"datasourceList":[{"name":"gsheet-selected","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"deleted":false,"gitSyncId":"6507db87f847163dfe7777c4_6507dc29f847163dfe7777d1"}],"customJSLibList":[],"pageList":[{"unpublishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":4896.0,"snapColumns":64.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":380.0,"containerStyle":"none","snapRows":124.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":86.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[{"boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","borderColor":"#E0DEDE","isVisibleDownload":true,"iconSVG":"/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg","topRow":0.0,"isSortable":true,"type":"TABLE_WIDGET_V2","inlineEditingSaveOption":"ROW_LEVEL","animateLoading":true,"dynamicBindingPathList":[{"key":"accentColor"},{"key":"borderRadius"},{"key":"boxShadow"},{"key":"tableData"},{"key":"primaryColumns.uniq_id.computedValue"},{"key":"primaryColumns.japanese_name.computedValue"},{"key":"primaryColumns.currencies.computedValue"},{"key":"primaryColumns.specialChars.computedValue"},{"key":"primaryColumns.product_name.computedValue"},{"key":"primaryColumns.manufacturer.computedValue"},{"key":"primaryColumns.price.computedValue"},{"key":"primaryColumns.number_available_in_stock.computedValue"},{"key":"primaryColumns.number_of_reviews.computedValue"},{"key":"primaryColumns.number_of_answered_questions.computedValue"},{"key":"primaryColumns.average_review_rating.computedValue"},{"key":"primaryColumns.amazon_category_and_sub_category.computedValue"},{"key":"primaryColumns.customers_who_bought_this_item_also_bought.computedValue"},{"key":"primaryColumns.rowIndex.computedValue"}],"needsHeightForContent":true,"leftColumn":0.0,"delimiter":",","defaultSelectedRowIndex":0.0,"accentColor":"{{appsmith.theme.colors.primaryColor}}","isVisibleFilters":true,"isVisible":true,"enableClientSideSearch":true,"version":2.0,"totalRecordsCount":0.0,"tags":["Suggested","Display"],"isLoading":false,"childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","columnUpdatedAt":1.695963199756E12,"defaultSelectedRowIndices":[0.0],"mobileBottomRow":29.0,"widgetName":"Table1","defaultPageSize":0.0,"columnOrder":["uniq_id","japanese_name","currencies","specialChars","product_name","manufacturer","price","number_available_in_stock","number_of_reviews","number_of_answered_questions","average_review_rating","amazon_category_and_sub_category","customers_who_bought_this_item_also_bought","rowIndex"],"dynamicPropertyPathList":[],"displayName":"Table","bottomRow":28.0,"columnWidthMap":{},"parentRowSpace":10.0,"hideCard":false,"mobileRightColumn":34.0,"parentColumnSpace":16.65625,"dynamicTriggerPathList":[],"borderWidth":"1","primaryColumns":{"uniq_id":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":0.0,"width":150.0,"originalId":"uniq_id","id":"uniq_id","alias":"uniq_id","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"uniq_id","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"uniq_id\"]))}}","sticky":"","validation":{}},"japanese_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":1.0,"width":150.0,"originalId":"japanese_name","id":"japanese_name","alias":"japanese_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"japanese_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"japanese_name\"]))}}","sticky":"","validation":{}},"currencies":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":2.0,"width":150.0,"originalId":"currencies","id":"currencies","alias":"currencies","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"currencies","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"currencies\"]))}}","sticky":"","validation":{}},"specialChars":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":3.0,"width":150.0,"originalId":"specialChars","id":"specialChars","alias":"specialChars","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"specialChars","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"specialChars\"]))}}","sticky":"","validation":{}},"product_name":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":4.0,"width":150.0,"originalId":"product_name","id":"product_name","alias":"product_name","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"product_name","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"product_name\"]))}}","sticky":"","validation":{}},"manufacturer":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":5.0,"width":150.0,"originalId":"manufacturer","id":"manufacturer","alias":"manufacturer","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"manufacturer","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"manufacturer\"]))}}","sticky":"","validation":{}},"price":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":6.0,"width":150.0,"originalId":"price","id":"price","alias":"price","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"price","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"price\"]))}}","sticky":"","validation":{}},"number_available_in_stock":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":7.0,"width":150.0,"originalId":"number_available_in_stock","id":"number_available_in_stock","alias":"number_available_in_stock","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_available_in_stock","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_available_in_stock\"]))}}","sticky":"","validation":{}},"number_of_reviews":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":8.0,"width":150.0,"originalId":"number_of_reviews","id":"number_of_reviews","alias":"number_of_reviews","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_reviews","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_reviews\"]))}}","sticky":"","validation":{}},"number_of_answered_questions":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":9.0,"width":150.0,"originalId":"number_of_answered_questions","id":"number_of_answered_questions","alias":"number_of_answered_questions","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"number_of_answered_questions","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"number_of_answered_questions\"]))}}","sticky":"","validation":{}},"average_review_rating":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":10.0,"width":150.0,"originalId":"average_review_rating","id":"average_review_rating","alias":"average_review_rating","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"average_review_rating","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"average_review_rating\"]))}}","sticky":"","validation":{}},"amazon_category_and_sub_category":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":11.0,"width":150.0,"originalId":"amazon_category_and_sub_category","id":"amazon_category_and_sub_category","alias":"amazon_category_and_sub_category","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"amazon_category_and_sub_category","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"amazon_category_and_sub_category\"]))}}","sticky":"","validation":{}},"customers_who_bought_this_item_also_bought":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":12.0,"width":150.0,"originalId":"customers_who_bought_this_item_also_bought","id":"customers_who_bought_this_item_also_bought","alias":"customers_who_bought_this_item_also_bought","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"customers_who_bought_this_item_also_bought","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"customers_who_bought_this_item_also_bought\"]))}}","sticky":"","validation":{}},"rowIndex":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":13.0,"width":150.0,"originalId":"rowIndex","id":"rowIndex","alias":"rowIndex","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"number","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"rowIndex","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"rowIndex\"]))}}","sticky":"","validation":{}}},"key":"y3e8fye419","canFreezeColumn":true,"isDeprecated":false,"rightColumn":34.0,"textSize":"0.875rem","widgetId":"5w278g8zo9","minWidth":450.0,"tableData":"{{fetch_many_selected_access.data}}","label":"Data","searchKey":"","parentId":"0","renderMode":"CANVAS","mobileTopRow":1.0,"horizontalAlignment":"LEFT","isVisibleSearch":true,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"isVisiblePagination":true,"verticalAlignment":"CENTER"}]},"layoutOnLoadActions":[[{"id":"Page1_fetch_many_selected_access","name":"fetch_many_selected_access","confirmBeforeExecute":false,"pluginType":"SAAS","jsonPathKeys":[],"timeoutInMillisecond":10000.0}]],"layoutOnLoadActionErrors":[],"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"publishedPage":{"name":"Page1","slug":"page1","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":1224.0,"snapColumns":16.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":1250.0,"containerStyle":"none","snapRows":33.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":4.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[]},"validOnPageLoadActions":true,"id":"Page1","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[]},"deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f37b43d9217d781a526"}],"actionList":[{"pluginType":"SAAS","pluginId":"google-sheets-plugin","unpublishedAction":{"name":"fetch_many_selected_access","datasource":{"name":"gsheet-selected","pluginId":"google-sheets-plugin","messages":[],"isAutoGenerated":false,"id":"gsheet-selected","deleted":false,"policies":[],"userPermissions":[]},"pageId":"Page1","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","encodeParamsToggle":true,"selfReferencingDataPaths":[],"formData":{"command":{"data":"FETCH_MANY"},"entityType":{"data":"ROWS"},"tableHeaderIndex":{"data":"1"},"projection":{"data":[]},"queryFormat":{"data":"ROWS"},"range":{"data":""},"where":{"data":{"condition":"AND","children":[{"condition":"LT"}]}},"pagination":{"data":{"limit":"20","offset":"0"}},"smartSubstitution":{"data":true},"sheetUrl":{"data":"https://docs.google.com/spreadsheets/d/1rD1Bo4x-y9B7EqaVs8HuJViGSEVBeiLPuTdxMoC2uDw/edit"},"sheetName":{"data":"Sheet1"},"sortBy":{"data":[{"column":"","order":"Ascending"}]}}},"executeOnLoad":true,"dynamicBindingPathList":[],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-29T04:59:00Z"},"publishedAction":{"datasource":{"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"messages":[],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[]},"id":"Page1_fetch_many_selected_access","deleted":false,"gitSyncId":"65164f37b43d9217d781a524_65164f5db43d9217d781a52b"}],"actionCollectionList":[],"updatedResources":{"customJSLibList":[],"actionList":["fetch_many_selected_access##ENTITY_SEPARATOR##Page1"],"pageList":["Page1"],"actionCollectionList":[]},"editModeTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false},"publishedTheme":{"name":"Default-New","displayName":"Modern","isSystemTheme":true,"deleted":false}} \ No newline at end of file diff --git a/app/client/cypress/fixtures/TestDataSet1.json b/app/client/cypress/fixtures/TestDataSet1.json index 9cad0333ad..6ae5371660 100644 --- a/app/client/cypress/fixtures/TestDataSet1.json +++ b/app/client/cypress/fixtures/TestDataSet1.json @@ -201,6 +201,162 @@ "orderAmount": 9.99 } ], + "Custom3DEChartConfig": { + "grid3D": { + "top": 0, + "bottom": 0 + }, + "tooltip": {}, + "xAxis3D": { + "type": "category" + }, + "yAxis3D": { + "type": "category" + }, + "zAxis3D": {}, + "visualMap": { + "max": 100000000, + "dimension": "Population", + "bottom": -50 + }, + "dataset": { + "dimensions": [ + "Income", + "Life Expectancy", + "Population", + "Country", + { + "name": "Year", + "type": "ordinal" + } + ], + "source": [ + [ + "Income", + "Life Expectancy", + "Population", + "Country", + "Year" + ], + [ + 37599, + 81.9, + 64395345, + "France", + 2015 + ], + [ + 44053, + 81.1, + 80688545, + "Germany", + 2015 + ], + [ + 42182, + 82.8, + 329425, + "Iceland", + 2015 + ], + [ + 5903, + 66.8, + 1311050527, + "India", + 2015 + ], + [ + 36162, + 83.5, + 126573481, + "Japan", + 2015 + ], + [ + 1390, + 71.4, + 25155317, + "North Korea", + 2015 + ], + [ + 34644, + 80.7, + 50293439, + "South Korea", + 2015 + ], + [ + 34186, + 80.6, + 4528526, + "New Zealand", + 2015 + ], + [ + 64304, + 81.6, + 5210967, + "Norway", + 2015 + ], + [ + 24787, + 77.3, + 38611794, + "Poland", + 2015 + ], + [ + 23038, + 73.13, + 143456918, + "Russia", + 2015 + ], + [ + 19360, + 76.5, + 78665830, + "Turkey", + 2015 + ], + [ + 38225, + 81.4, + 64715810, + "United Kingdom", + 2015 + ], + [ + 53354, + 79.1, + 321773631, + "United States", + 2015 + ] + ] + }, + "series": [ + { + "type": "bar3D", + "shading": "lambert", + "encode": { + "x": "Year", + "y": "Country", + "z": "Life Expectancy", + "tooltip": [ + 0, + 1, + 2, + 3, + 4 + ] + } + } + ] + }, "ChartCustomConfig": { "type":"column2d", "dataSource":{ diff --git a/app/client/cypress/fixtures/chartUpdatedDsl.json b/app/client/cypress/fixtures/chartUpdatedDsl.json index bd48114539..1fb7e865c4 100644 --- a/app/client/cypress/fixtures/chartUpdatedDsl.json +++ b/app/client/cypress/fixtures/chartUpdatedDsl.json @@ -120,6 +120,7 @@ "data": "" } }, + "customFusionChartConfig": {}, "yAxisName": "Total Order Revenue $", "parentColumnSpace": 14.59375, "dynamicTriggerPathList": [], diff --git a/app/client/cypress/fixtures/listV2AudioVideoDsl.json b/app/client/cypress/fixtures/listV2AudioVideoDsl.json new file mode 100644 index 0000000000..76b5182b98 --- /dev/null +++ b/app/client/cypress/fixtures/listV2AudioVideoDsl.json @@ -0,0 +1,575 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 380, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 6, + "pageSize": 1, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8, + "animateLoading": true, + "dynamicBindingPathList": [ + { + "key": "currentItemsView" + }, + { + "key": "selectedItemView" + }, + { + "key": "triggeredItemView" + }, + { + "key": "primaryKeys" + }, + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "leftColumn": 6, + "enhancements": true, + "children": [ + { + "mobileBottomRow": 400, + "widgetName": "Canvas1", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 310, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400, + "mobileRightColumn": 129.375, + "noPad": true, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12, + "widgetName": "Container1", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": [ + "div", + "parent", + "group" + ], + "topRow": 0, + "bottomRow": 25, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64, + "animateLoading": true, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "widgetName": "Canvas2", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 250, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Image1", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0, + "bottomRow": 8, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { + "key": "image" + }, + { + "key": "borderRadius" + } + ], + "leftColumn": 0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "25ukodbr6c", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 16, + "objectFit": "cover", + "widgetId": "em3jvrn5am", + "isVisible": true, + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "maxZoomLevel": 1, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0, + "bottomRow": 4, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "9jmg2z05f9", + "isDeprecated": false, + "rightColumn": 28, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "3j2sl88xb8", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4, + "bottomRow": 8, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "9jmg2z05f9", + "isDeprecated": false, + "rightColumn": 24, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "jva2x1emu9", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 9, + "widgetName": "AudioRecorder1", + "displayName": "Audio Recorder", + "iconSVG": "/static/media/icon.c7fb58d71a30a6fbe9c922faae21e621.svg", + "searchTags": [ + "sound recorder", + "voice recorder" + ], + "topRow": 12, + "bottomRow": 19, + "parentRowSpace": 10, + "type": "AUDIO_RECORDER_WIDGET", + "hideCard": false, + "mobileRightColumn": 54, + "animateLoading": true, + "parentColumnSpace": 8.06591796875, + "leftColumn": 35, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + } + ], + "isDisabled": false, + "key": "b2l6u93gjl", + "isDeprecated": false, + "rightColumn": 59, + "dynamicHeight": "FIXED", + "widgetId": "1z847p7y12", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "External" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 2, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 38, + "iconColor": "white" + }, + { + "mobileBottomRow": 7, + "widgetName": "Audio1", + "displayName": "Audio", + "iconSVG": "/static/media/icon.90965be2578a5c1c8e2996b65e5b6988.svg", + "searchTags": [ + "mp3", + "sound", + "wave", + "player" + ], + "topRow": 3, + "bottomRow": 7, + "parentRowSpace": 10, + "type": "AUDIO_WIDGET", + "hideCard": false, + "mobileRightColumn": 61, + "animateLoading": true, + "parentColumnSpace": 8.06591796875, + "leftColumn": 33, + "dynamicBindingPathList": [], + "key": "vtr3jxeug0", + "isDeprecated": false, + "rightColumn": 61, + "dynamicHeight": "FIXED", + "widgetId": "tq2w2qwe8o", + "minWidth": 450, + "isVisible": true, + "version": 1, + "url": "https://assets.appsmith.com/widgets/birds_chirping.mp3", + "parentId": "5gw7cd9vgs", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 3, + "responsiveBehavior": "fill", + "mobileLeftColumn": 33, + "autoPlay": false + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 40, + "widgetName": "Video1", + "displayName": "Video", + "iconSVG": "/static/media/icon.e3e5dfc92ff10e68a8a2b3c94ab4a4a4.svg", + "searchTags": [ + "youtube" + ], + "topRow": 10, + "bottomRow": 21, + "parentRowSpace": 10, + "type": "VIDEO_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "parentColumnSpace": 8.06591796875, + "leftColumn": 6, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "key": "e4bzeq4760", + "backgroundColor": "#000", + "isDeprecated": false, + "rightColumn": 23, + "dynamicHeight": "FIXED", + "widgetId": "91brup20hv", + "isVisible": true, + "version": 1, + "url": "https://assets.appsmith.com/widgets/bird.mp4", + "parentId": "5gw7cd9vgs", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 12, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 4, + "autoPlay": false + } + ], + "key": "hzwclegot4", + "isDeprecated": false, + "detachFromLayout": true, + "widgetId": "5gw7cd9vgs", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "k2be0wkm71", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "80p0p01sv9", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64, + "dynamicHeight": "FIXED", + "widgetId": "k2be0wkm71", + "containerStyle": "card", + "minWidth": 450, + "isVisible": true, + "version": 1, + "isListItemContainer": true, + "parentId": "mmnmpsy0uj", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": [ + "dynamicHeight" + ], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 10 + } + ], + "key": "hzwclegot4", + "isDeprecated": false, + "rightColumn": 129.375, + "detachFromLayout": true, + "widgetId": "mmnmpsy0uj", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "rf79rl326i", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": [ + "Suggested", + "Display" + ], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "mmnmpsy0uj", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 46, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List1", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 37, + "parentRowSpace": 10, + "hideCard": false, + "templateBottomRow": 16, + "mobileRightColumn": 41, + "mainContainerId": "k2be0wkm71", + "primaryKeys": "{{List1.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 5.390625, + "dynamicTriggerPathList": [], + "gridType": "vertical", + "key": "idsqgrps32", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 60, + "widgetId": "rf79rl326i", + "minWidth": 450, + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 6, + "responsiveBehavior": "fill", + "mobileLeftColumn": 17, + "selectedItemView": "{{{}}}" + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/fixtures/listV2ButtonsDsl.json b/app/client/cypress/fixtures/listV2ButtonsDsl.json new file mode 100644 index 0000000000..08fde58109 --- /dev/null +++ b/app/client/cypress/fixtures/listV2ButtonsDsl.json @@ -0,0 +1,744 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 460, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 6, + "pageSize": 1, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8, + "animateLoading": true, + "dynamicBindingPathList": [ + { + "key": "currentItemsView" + }, + { + "key": "selectedItemView" + }, + { + "key": "triggeredItemView" + }, + { + "key": "primaryKeys" + }, + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "leftColumn": 6, + "enhancements": true, + "children": [ + { + "mobileBottomRow": 400, + "widgetName": "Canvas1", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 310, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400, + "mobileRightColumn": 129.375, + "noPad": true, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12, + "widgetName": "Container1", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": [ + "div", + "parent", + "group" + ], + "topRow": 0, + "bottomRow": 25, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64, + "animateLoading": true, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "widgetName": "Canvas2", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 250, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Image1", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0, + "bottomRow": 8, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { + "key": "image" + }, + { + "key": "borderRadius" + } + ], + "leftColumn": 0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "25ukodbr6c", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 16, + "objectFit": "cover", + "widgetId": "em3jvrn5am", + "isVisible": true, + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "maxZoomLevel": 1, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0, + "bottomRow": 4, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "9jmg2z05f9", + "isDeprecated": false, + "rightColumn": 28, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "3j2sl88xb8", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4, + "bottomRow": 8, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "9jmg2z05f9", + "isDeprecated": false, + "rightColumn": 24, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "jva2x1emu9", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 13, + "widgetName": "ButtonGroup1", + "isCanvas": false, + "displayName": "Button Group", + "iconSVG": "/static/media/icon.bb8db4853027d74a78963c3375841e4b.svg", + "searchTags": [ + "click", + "submit" + ], + "topRow": 9, + "bottomRow": 13, + "parentRowSpace": 10, + "groupButtons": { + "groupButton1": { + "label": "Favorite", + "iconName": "heart", + "id": "groupButton1", + "widgetId": "", + "buttonType": "SIMPLE", + "placement": "CENTER", + "isVisible": true, + "isDisabled": false, + "index": 0, + "menuItems": {}, + "buttonColor": "{{appsmith.theme.colors.primaryColor}}" + }, + "groupButton2": { + "label": "Add", + "iconName": "add", + "id": "groupButton2", + "buttonType": "SIMPLE", + "placement": "CENTER", + "widgetId": "", + "isVisible": true, + "isDisabled": false, + "index": 1, + "menuItems": {}, + "buttonColor": "{{appsmith.theme.colors.primaryColor}}" + }, + "groupButton3": { + "label": "More", + "iconName": "more", + "id": "groupButton3", + "buttonType": "MENU", + "placement": "CENTER", + "widgetId": "", + "isVisible": true, + "isDisabled": false, + "index": 2, + "menuItems": { + "menuItem1": { + "label": "First Option", + "backgroundColor": "#FFFFFF", + "id": "menuItem1", + "widgetId": "", + "onClick": "", + "isVisible": true, + "isDisabled": false, + "index": 0 + }, + "menuItem2": { + "label": "Second Option", + "backgroundColor": "#FFFFFF", + "id": "menuItem2", + "widgetId": "", + "onClick": "", + "isVisible": true, + "isDisabled": false, + "index": 1 + }, + "menuItem3": { + "label": "Delete", + "iconName": "trash", + "iconColor": "#FFFFFF", + "iconAlign": "right", + "textColor": "#FFFFFF", + "backgroundColor": "#DD4B34", + "id": "menuItem3", + "widgetId": "", + "onClick": "", + "isVisible": true, + "isDisabled": false, + "index": 2 + } + }, + "buttonColor": "{{appsmith.theme.colors.primaryColor}}" + } + }, + "type": "BUTTON_GROUP_WIDGET", + "hideCard": false, + "mobileRightColumn": 54, + "animateLoading": true, + "parentColumnSpace": 4.4140625, + "leftColumn": 29, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "groupButtons.groupButton1.buttonColor" + }, + { + "key": "groupButtons.groupButton2.buttonColor" + }, + { + "key": "groupButtons.groupButton3.buttonColor" + } + ], + "key": "7r7px2hmgm", + "orientation": "horizontal", + "isDeprecated": false, + "rightColumn": 62, + "dynamicHeight": "FIXED", + "widgetId": "zu0qwe3wls", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Buttons" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 9, + "responsiveBehavior": "fill", + "childStylesheet": { + "button": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}" + } + }, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 30, + "buttonVariant": "PRIMARY" + }, + { + "boxShadow": "none", + "mobileBottomRow": 20, + "widgetName": "IconButton1", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": [ + "click", + "submit" + ], + "topRow": 15, + "bottomRow": 19, + "parentRowSpace": 10, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 32, + "animateLoading": true, + "parentColumnSpace": 4.4140625, + "leftColumn": 44, + "dynamicBindingPathList": [ + { + "key": "buttonColor" + }, + { + "key": "borderRadius" + } + ], + "isDisabled": false, + "key": "qs1re01jva", + "isDeprecated": false, + "rightColumn": 48, + "iconName": "plus", + "dynamicHeight": "FIXED", + "widgetId": "mugp61q9le", + "minWidth": 50, + "isVisible": true, + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Buttons" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 16, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 28, + "buttonVariant": "PRIMARY" + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 6, + "widgetName": "Button1", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": [ + "click", + "submit" + ], + "topRow": 2, + "bottomRow": 6, + "parentRowSpace": 10, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 54, + "animateLoading": true, + "parentColumnSpace": 8.06591796875, + "leftColumn": 38, + "dynamicBindingPathList": [ + { + "key": "buttonColor" + }, + { + "key": "borderRadius" + } + ], + "text": "Submit", + "isDisabled": false, + "key": "rolryyfj5e", + "isDeprecated": false, + "rightColumn": 54, + "isDefaultClickDisabled": true, + "dynamicHeight": "FIXED", + "widgetId": "8nrnhbbekm", + "minWidth": 120, + "isVisible": true, + "recaptchaType": "V3", + "version": 1, + "parentId": "5gw7cd9vgs", + "tags": [ + "Buttons" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 2, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 38, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ], + "key": "hzwclegot4", + "isDeprecated": false, + "detachFromLayout": true, + "widgetId": "5gw7cd9vgs", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "k2be0wkm71", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "80p0p01sv9", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64, + "dynamicHeight": "FIXED", + "widgetId": "k2be0wkm71", + "containerStyle": "card", + "minWidth": 450, + "isVisible": true, + "version": 1, + "isListItemContainer": true, + "parentId": "mmnmpsy0uj", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": [ + "dynamicHeight" + ], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 10 + } + ], + "key": "hzwclegot4", + "isDeprecated": false, + "rightColumn": 129.375, + "detachFromLayout": true, + "widgetId": "mmnmpsy0uj", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "rf79rl326i", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": [ + "Suggested", + "Display" + ], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "mmnmpsy0uj", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 46, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List1", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 37, + "parentRowSpace": 10, + "hideCard": false, + "templateBottomRow": 16, + "mobileRightColumn": 41, + "mainContainerId": "k2be0wkm71", + "primaryKeys": "{{List1.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 5.390625, + "dynamicTriggerPathList": [], + "gridType": "vertical", + "key": "idsqgrps32", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 60, + "widgetId": "rf79rl326i", + "minWidth": 450, + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 6, + "responsiveBehavior": "fill", + "mobileLeftColumn": 17, + "selectedItemView": "{{{}}}" + }, + { + "mobileBottomRow": 46, + "widgetName": "Text3", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 42, + "bottomRow": 46, + "parentRowSpace": 10, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 5.75, + "dynamicTriggerPathList": [], + "leftColumn": 7, + "dynamicBindingPathList": [ + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{Audio1.autoPlay}}", + "key": "9jmg2z05f9", + "isDeprecated": false, + "rightColumn": 28, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "he7knga5hk", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "0", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 42, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 12, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "minDynamicHeight": 4 + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/fixtures/listV2NestedDsl.json b/app/client/cypress/fixtures/listV2NestedDsl.json new file mode 100644 index 0000000000..d2f772e7c9 --- /dev/null +++ b/app/client/cypress/fixtures/listV2NestedDsl.json @@ -0,0 +1,1266 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 480, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 8, + "pageSize": 1, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8, + "animateLoading": true, + "dynamicBindingPathList": [ + { + "key": "currentItemsView" + }, + { + "key": "selectedItemView" + }, + { + "key": "triggeredItemView" + }, + { + "key": "primaryKeys" + }, + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "leftColumn": 3, + "enhancements": true, + "children": [ + { + "mobileBottomRow": 400, + "widgetName": "Canvas1", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 400, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400, + "mobileRightColumn": 241.875, + "noPad": true, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12, + "widgetName": "Container1", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": [ + "div", + "parent", + "group" + ], + "topRow": 0, + "bottomRow": 30, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64, + "animateLoading": true, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "widgetName": "Canvas2", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 410, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Image1", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0, + "bottomRow": 8, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { + "key": "image" + }, + { + "key": "borderRadius" + } + ], + "leftColumn": 0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "crx5qmd37r", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 6, + "objectFit": "cover", + "widgetId": "7jtknqp637", + "isVisible": true, + "version": 1, + "parentId": "ol98v0nauw", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "maxZoomLevel": 1, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0, + "bottomRow": 4, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 6, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "yuohbv56yb", + "isDeprecated": false, + "rightColumn": 13, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "y9bu3znw9w", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "ol98v0nauw", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4, + "bottomRow": 8, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 6, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "yuohbv56yb", + "isDeprecated": false, + "rightColumn": 14, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "xq7ogky1ek", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "ol98v0nauw", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 1, + "pageSize": 1, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8, + "animateLoading": true, + "dynamicBindingPathList": [ + { + "key": "currentItemsView" + }, + { + "key": "selectedItemView" + }, + { + "key": "triggeredItemView" + }, + { + "key": "primaryKeys" + }, + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "leftColumn": 15, + "enhancements": true, + "children": [ + { + "mobileBottomRow": 400, + "widgetName": "Canvas3", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 400, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400, + "mobileRightColumn": 212.478515625, + "noPad": true, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12, + "widgetName": "Container2", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": [ + "div", + "parent", + "group" + ], + "topRow": 0, + "bottomRow": 21, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64, + "animateLoading": true, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "widgetName": "Canvas4", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 420, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Image2", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0, + "bottomRow": 8, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { + "key": "image" + }, + { + "key": "borderRadius" + } + ], + "leftColumn": 0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "crx5qmd37r", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 10, + "objectFit": "cover", + "widgetId": "ppxsqo3xi3", + "isVisible": true, + "version": 1, + "parentId": "nr21lirg0s", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "maxZoomLevel": 1, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4, + "widgetName": "Text3", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0, + "bottomRow": 4, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 10, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "yuohbv56yb", + "isDeprecated": false, + "rightColumn": 18, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "qi0kgfr7y9", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "nr21lirg0s", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Text4", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4, + "bottomRow": 8, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 10, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "yuohbv56yb", + "isDeprecated": false, + "rightColumn": 18, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "sd9wakjd2z", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "nr21lirg0s", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 1, + "pageSize": 2, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8, + "animateLoading": true, + "dynamicBindingPathList": [ + { + "key": "currentItemsView" + }, + { + "key": "selectedItemView" + }, + { + "key": "triggeredItemView" + }, + { + "key": "primaryKeys" + }, + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "leftColumn": 19, + "enhancements": true, + "children": [ + { + "mobileBottomRow": 400, + "widgetName": "Canvas5", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 410, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400, + "mobileRightColumn": 125.61904907226562, + "noPad": true, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12, + "widgetName": "Container3", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": [ + "div", + "parent", + "group" + ], + "topRow": 0, + "bottomRow": 16, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64, + "animateLoading": true, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "widgetName": "Canvas6", + "displayName": "Canvas", + "topRow": 0, + "bottomRow": 160, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Image3", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0, + "bottomRow": 8, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { + "key": "image" + }, + { + "key": "borderRadius" + } + ], + "leftColumn": 0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "crx5qmd37r", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 16, + "objectFit": "cover", + "widgetId": "9upugl3s6w", + "isVisible": true, + "version": 1, + "parentId": "2pouri974m", + "tags": [ + "Media" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "maxZoomLevel": 1, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4, + "widgetName": "Text5", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0, + "bottomRow": 4, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "yuohbv56yb", + "isDeprecated": false, + "rightColumn": 28, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "2nszqy55yh", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "2pouri974m", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8, + "widgetName": "Text6", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4, + "bottomRow": 8, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { + "key": "text" + }, + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "leftColumn": 16, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "yuohbv56yb", + "isDeprecated": false, + "rightColumn": 24, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "i9yku1ea41", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "2pouri974m", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4 + } + ], + "key": "teo0eoo7v5", + "isDeprecated": false, + "detachFromLayout": true, + "widgetId": "2pouri974m", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "9jex51m7on", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "53b9m5q19s", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64, + "dynamicHeight": "FIXED", + "widgetId": "9jex51m7on", + "containerStyle": "card", + "minWidth": 450, + "isVisible": true, + "version": 1, + "isListItemContainer": true, + "parentId": "4xoxmbu604", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": [ + "dynamicHeight" + ], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 10 + } + ], + "key": "teo0eoo7v5", + "isDeprecated": false, + "rightColumn": 125.61904907226562, + "detachFromLayout": true, + "widgetId": "4xoxmbu604", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "eh9e166oin", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": [ + "Suggested", + "Display" + ], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "4xoxmbu604", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 42, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List3", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 42, + "parentRowSpace": 10, + "hideCard": false, + "templateBottomRow": 16, + "mobileRightColumn": 60, + "mainContainerId": "9jex51m7on", + "primaryKeys": "{{List3.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 5.234127044677734, + "dynamicTriggerPathList": [], + "gridType": "vertical", + "key": "49evlgkqy4", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 63, + "widgetId": "eh9e166oin", + "minWidth": 450, + "parentId": "nr21lirg0s", + "renderMode": "CANVAS", + "mobileTopRow": 2, + "responsiveBehavior": "fill", + "mobileLeftColumn": 36, + "selectedItemView": "{{{}}}" + } + ], + "key": "teo0eoo7v5", + "isDeprecated": false, + "detachFromLayout": true, + "widgetId": "nr21lirg0s", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "6saon21lgg", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "53b9m5q19s", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64, + "dynamicHeight": "FIXED", + "widgetId": "6saon21lgg", + "containerStyle": "card", + "minWidth": 450, + "isVisible": true, + "version": 1, + "isListItemContainer": true, + "parentId": "qdhuogthdu", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": [ + "dynamicHeight" + ], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 10 + } + ], + "key": "teo0eoo7v5", + "isDeprecated": false, + "rightColumn": 212.478515625, + "detachFromLayout": true, + "widgetId": "qdhuogthdu", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "htol7qtxpg", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": [ + "Suggested", + "Display" + ], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "qdhuogthdu", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 41, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List2", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 41, + "parentRowSpace": 10, + "hideCard": false, + "templateBottomRow": 16, + "mobileRightColumn": 56, + "mainContainerId": "6saon21lgg", + "primaryKeys": "{{List2.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 8.853271484375, + "dynamicTriggerPathList": [], + "gridType": "vertical", + "key": "49evlgkqy4", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 64, + "widgetId": "htol7qtxpg", + "minWidth": 450, + "parentId": "ol98v0nauw", + "renderMode": "CANVAS", + "mobileTopRow": 1, + "responsiveBehavior": "fill", + "mobileLeftColumn": 32, + "selectedItemView": "{{{}}}" + } + ], + "key": "teo0eoo7v5", + "isDeprecated": false, + "detachFromLayout": true, + "widgetId": "ol98v0nauw", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "zgrylvxsat", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "53b9m5q19s", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64, + "dynamicHeight": "FIXED", + "widgetId": "zgrylvxsat", + "containerStyle": "card", + "minWidth": 450, + "isVisible": true, + "version": 1, + "isListItemContainer": true, + "parentId": "lyr1fx5jgn", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": [ + "dynamicHeight" + ], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 10 + } + ], + "key": "teo0eoo7v5", + "isDeprecated": false, + "rightColumn": 241.875, + "detachFromLayout": true, + "widgetId": "lyr1fx5jgn", + "containerStyle": "none", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "u9ykpts75q", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": [ + "Suggested", + "Display" + ], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "lyr1fx5jgn", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 48, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List1", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 88, + "parentRowSpace": 10, + "hideCard": false, + "templateBottomRow": 16, + "mobileRightColumn": 41, + "mainContainerId": "zgrylvxsat", + "primaryKeys": "{{List1.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 10.078125, + "dynamicTriggerPathList": [], + "gridType": "vertical", + "key": "49evlgkqy4", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 62, + "widgetId": "u9ykpts75q", + "minWidth": 450, + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 8, + "responsiveBehavior": "fill", + "mobileLeftColumn": 17, + "selectedItemView": "{{{}}}" + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/fixtures/listwidgetdsl.json b/app/client/cypress/fixtures/listwidgetdsl.json index f568a4c832..f34952103f 100644 --- a/app/client/cypress/fixtures/listwidgetdsl.json +++ b/app/client/cypress/fixtures/listwidgetdsl.json @@ -172,7 +172,7 @@ "type": "LIST_WIDGET", "isLoading": false, "parentColumnSpace": 57.875, - "parentRowSpace": 40, + "parentRowSpace": 10, "leftColumn": 4, "rightColumn": 12, "topRow": 2, diff --git a/app/client/cypress/fixtures/modalWidgetTestApp.json b/app/client/cypress/fixtures/modalWidgetTestApp.json new file mode 100644 index 0000000000..388b7c8c14 --- /dev/null +++ b/app/client/cypress/fixtures/modalWidgetTestApp.json @@ -0,0 +1,7571 @@ +{ + "clientSchemaVersion": 1.0, + "serverSchemaVersion": 6.0, + "exportedApplication": { + "name": "ModalWidgetTestApp", + "isPublic": false, + "pages": [{ "id": "Page1", "isDefault": true }], + "publishedPages": [{ "id": "Page1", "isDefault": true }], + "viewMode": false, + "appIsExample": false, + "unreadCommentThreads": 0.0, + "color": "#C7F3F0", + "icon": "flight", + "slug": "modalwidgettestapp", + "unpublishedCustomJSLibs": [], + "publishedCustomJSLibs": [], + "evaluationVersion": 2.0, + "applicationVersion": 2.0, + "collapseInvisibleWidgets": true, + "isManualUpdate": false, + "deleted": false + }, + "datasourceList": [], + "customJSLibList": [], + "pageList": [ + { + "unpublishedPage": { + "name": "Page1", + "slug": "page1", + "layouts": [ + { + "viewMode": false, + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896.0, + "snapColumns": 64.0, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0.0, + "bottomRow": 1180.0, + "containerStyle": "none", + "snapRows": 124.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86.0, + "minHeight": 1292.0, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1.0, + "dynamicBindingPathList": [], + "leftColumn": 0.0, + "children": [ + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 12.0, + "widgetName": "Button1", + "onClick": "{{showModal('Modal1');}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 8.0, + "bottomRow": 12.0, + "parentRowSpace": 10.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 38.0, + "animateLoading": true, + "parentColumnSpace": 9.859375, + "dynamicTriggerPathList": [{ "key": "onClick" }], + "leftColumn": 22.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Submit", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 38.0, + "isDefaultClickDisabled": true, + "widgetId": "37aleq6qhk", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "0", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 8.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 22.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal1", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 190.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "minHeight": 1900.0, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas1", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 1900.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton1", + "onClick": "{{closeModal('Modal1')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "xvq75i05gs", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 1.0, + "bottomRow": 7.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 1.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Widgets Modal", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 41.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "vms8z4v4t9", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "originalTopRow": 1.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 5.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.f2c34197dbcf03595098986de898928f.svg", + "topRow": 7.0, + "labelWidth": 5.0, + "type": "INPUT_WIDGET_V2", + "animateLoading": true, + "resetOnSubmit": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" } + ], + "labelStyle": "", + "inputType": "TEXT", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": false, + "isVisible": true, + "version": 2.0, + "tags": ["Suggested", "Inputs"], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 12.0, + "mobileBottomRow": 13.0, + "widgetName": "Input1", + "displayName": "Input", + "searchTags": [ + "form", + "text input", + "number", + "textarea" + ], + "bottomRow": 14.0, + "parentRowSpace": 10.0, + "autoFocus": false, + "hideCard": false, + "mobileRightColumn": 23.0, + "parentColumnSpace": 6.9375, + "labelPosition": "Top", + "key": "m9ve3ppio8", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 24.0, + "widgetId": "qg5qem3xyp", + "minWidth": 450.0, + "label": "Label", + "parentId": "59hk3a5cny", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 6.0, + "responsiveBehavior": "fill", + "originalTopRow": 5.0, + "mobileLeftColumn": 3.0, + "maxDynamicHeight": 9000.0, + "iconAlign": "left", + "defaultText": "", + "minDynamicHeight": 4.0 + }, + { + "mobileBottomRow": 12.0, + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 7.0, + "bottomRow": 54.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 46.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [], + "leftColumn": 24.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{Table1.selectedRow}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 63.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ykifd3nlwx", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 8.0, + "responsiveBehavior": "fill", + "originalTopRow": 5.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 30.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 49.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.a7b19dc8b31d68fcff57f1d2c0084a18.svg", + "labelText": "Label", + "topRow": 55.0, + "labelWidth": 5.0, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "defaultOptionValue": "GREEN", + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "sourceData" } + ], + "placeholderText": "Select option", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Select"], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 57.0, + "mobileBottomRow": 20.0, + "widgetName": "Select1", + "isFilterable": true, + "dynamicPropertyPathList": [{ "key": "sourceData" }], + "displayName": "Select", + "searchTags": ["dropdown"], + "bottomRow": 62.0, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 21.0, + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [], + "labelPosition": "Top", + "sourceData": "[\n {\n \"name\": {{Input1.text}},\n \"code\": {{Input1.text}}\n },\n {\n \"name\": {{Input1.text+1}},\n \"code\": {{Input1.text+1}}\n },\n {\n \"name\": {{Input1.text+2}},\n \"code\": {{Input1.text+2}}\n }\n]", + "key": "9go22qpbuu", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 30.0, + "widgetId": "yg4ihellt5", + "optionValue": "code", + "minWidth": 450.0, + "parentId": "59hk3a5cny", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 13.0, + "optionLabel": "name", + "responsiveBehavior": "fill", + "originalTopRow": 50.0, + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 67.0, + "pageSize": 3.0, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8.0, + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "currentItemsView" }, + { "key": "selectedItemView" }, + { "key": "triggeredItemView" }, + { "key": "primaryKeys" }, + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "leftColumn": 0.0, + "enhancements": true, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 400.0, + "widgetName": "Canvas2", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 400.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400.0, + "mobileRightColumn": 166.5, + "noPad": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12.0, + "widgetName": "Container1", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 0.0, + "bottomRow": 12.0, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "widgetName": "Canvas3", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 120.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Image1", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0.0, + "bottomRow": 8.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16.0, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { "key": "borderRadius" } + ], + "leftColumn": 0.0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "an3dz32jnz", + "image": "https://jpeg.org/images/jpegsystems-home.jpg", + "isDeprecated": false, + "rightColumn": 16.0, + "objectFit": "cover", + "widgetId": "gn9wku1gs7", + "isVisible": true, + "version": 1.0, + "parentId": "rtjo8735m7", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "Text3", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 42.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "5dkd0u3zh7", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "rtjo8735m7", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Text4", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4.0, + "bottomRow": 8.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 40.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "684malsbtw", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "rtjo8735m7", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "rtjo8735m7", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "5m236c6iz7", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "8nbypdc1zz", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64.0, + "dynamicHeight": "FIXED", + "widgetId": "5m236c6iz7", + "containerStyle": "card", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "isListItemContainer": true, + "parentId": "cq5f7mkbyh", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": ["dynamicHeight"], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 10.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 166.5, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "cq5f7mkbyh", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "twucvyhokg", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": ["Suggested", "Display"], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "cq5f7mkbyh", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 102.0, + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 62.0, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List1", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 107.0, + "parentRowSpace": 10.0, + "hideCard": false, + "templateBottomRow": 16.0, + "mobileRightColumn": 24.0, + "mainContainerId": "5m236c6iz7", + "primaryKeys": "{{List1.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 6.9375, + "gridType": "vertical", + "key": "mgbk7d2119", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 62.0, + "widgetId": "twucvyhokg", + "minWidth": 450.0, + "parentId": "59hk3a5cny", + "renderMode": "CANVAS", + "mobileTopRow": 22.0, + "responsiveBehavior": "fill", + "originalTopRow": 62.0, + "mobileLeftColumn": 0.0, + "selectedItemView": "{{{}}}" + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "iconSVG": "/static/media/icon.46adf7030d667f0ad9002aa31f997573.svg", + "onSubmit": "{{showAlert('Form submitted!', 'success');}}", + "topRow": 107.0, + "type": "JSON_FORM_WIDGET", + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "submitButtonStyles.buttonColor" }, + { "key": "submitButtonStyles.borderRadius" }, + { "key": "resetButtonStyles.buttonColor" }, + { "key": "resetButtonStyles.borderRadius" }, + { + "key": "schema.__root_schema__.children.name.defaultValue" + }, + { + "key": "schema.__root_schema__.children.name.accentColor" + }, + { + "key": "schema.__root_schema__.children.name.borderRadius" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.accentColor" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.borderRadius" + }, + { + "key": "schema.__root_schema__.children.employee_id.defaultValue" + }, + { + "key": "schema.__root_schema__.children.employee_id.accentColor" + }, + { + "key": "schema.__root_schema__.children.employee_id.borderRadius" + }, + { "key": "schema.__root_schema__.defaultValue" }, + { "key": "schema.__root_schema__.borderRadius" }, + { "key": "schema.__root_schema__.cellBorderRadius" } + ], + "showReset": true, + "dynamicHeight": "FIXED", + "autoGenerateForm": true, + "resetButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "SECONDARY" + }, + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Layout"], + "isLoading": false, + "submitButtonLabel": "Submit", + "childStylesheet": { + "ARRAY": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "OBJECT": { + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "CHECKBOX": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + }, + "CURRENCY_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "DATEPICKER": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "EMAIL_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTISELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTILINE_TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PASSWORD_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PHONE_NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "RADIO_GROUP": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "SELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "SWITCH": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + } + }, + "disabledWhenInvalid": true, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 142.0, + "useSourceData": false, + "schema": { + "__root_schema__": { + "children": { + "name": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.name))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Text Input", + "sourceData": "John", + "isCustomField": false, + "accessor": "name", + "identifier": "name", + "position": 0.0, + "originalIdentifier": "name", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Name" + }, + "date_of_birth": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (moment(sourceData.date_of_birth, \"DD/MM/YYYY\").format(\"YYYY-MM-DDTHH:mm:ss.sssZ\")))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Datepicker", + "sourceData": "20/02/1990", + "isCustomField": false, + "accessor": "date_of_birth", + "identifier": "date_of_birth", + "position": 1.0, + "originalIdentifier": "date_of_birth", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "closeOnSelection": false, + "convertToISO": false, + "dateFormat": "DD/MM/YYYY", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "label": "Date Of Birth", + "maxDate": "2121-12-31T18:29:00.000Z", + "minDate": "1920-12-31T18:30:00.000Z", + "shortcuts": false, + "timePrecision": "minute", + "labelTextSize": "0.875rem" + }, + "employee_id": { + "children": {}, + "dataType": "number", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.employee_id))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Number Input", + "sourceData": 1001.0, + "isCustomField": false, + "accessor": "employee_id", + "identifier": "employee_id", + "position": 2.0, + "originalIdentifier": "employee_id", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Employee Id" + } + }, + "dataType": "object", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Object", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "isCustomField": false, + "accessor": "__root_schema__", + "identifier": "__root_schema__", + "position": -1.0, + "originalIdentifier": "__root_schema__", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "cellBorderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "cellBoxShadow": "none", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "" + } + }, + "mobileBottomRow": 54.0, + "widgetName": "JSONForm1", + "submitButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "PRIMARY" + }, + "dynamicPropertyPathList": [ + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + } + ], + "displayName": "JSON Form", + "bottomRow": 147.0, + "fieldLimitExceeded": false, + "parentRowSpace": 10.0, + "title": "Form", + "hideCard": false, + "mobileRightColumn": 42.0, + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [{ "key": "onSubmit" }], + "borderWidth": "1", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "resetButtonLabel": "Reset", + "key": "csjsvvwmwh", + "backgroundColor": "#fff", + "isDeprecated": false, + "rightColumn": 64.0, + "widgetId": "2pnkf5v8uj", + "minWidth": 450.0, + "parentId": "59hk3a5cny", + "renderMode": "CANVAS", + "mobileTopRow": 13.0, + "scrollContents": true, + "responsiveBehavior": "fill", + "fixedFooter": true, + "originalTopRow": 102.0, + "mobileLeftColumn": 17.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 67.0, + "widgetName": "Image2", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 54.0, + "bottomRow": 67.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 50.0, + "animateLoading": true, + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 32.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/5eeea355389655.59822ff824b72.gif", + "key": "an3dz32jnz", + "image": "", + "isDeprecated": false, + "rightColumn": 63.0, + "objectFit": "cover", + "widgetId": "h24avxj5g0", + "isVisible": true, + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 55.0, + "maxZoomLevel": 1.0, + "enableDownload": false, + "originalTopRow": 49.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 38.0, + "originalBottomRow": 62.0, + "enableRotation": false + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 74.0, + "widgetName": "Container2", + "borderColor": "#E0DEDE", + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 148.0, + "bottomRow": 188.0, + "parentRowSpace": 10.0, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 26.0, + "animateLoading": true, + "parentColumnSpace": 6.9375, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 100.0, + "widgetName": "Canvas4", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 400.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "minHeight": 100.0, + "mobileRightColumn": 166.5, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 19.0, + "widgetName": "Tabs1", + "borderColor": "#E0DEDE", + "isCanvas": true, + "displayName": "Tabs", + "iconSVG": "/static/media/icon.9e3d67c0af9c0bd092dc56240314e18a.svg", + "topRow": 4.0, + "bottomRow": 38.0, + "parentRowSpace": 10.0, + "type": "TABS_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 28.0, + "animateLoading": true, + "parentColumnSpace": 2.939453125, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "tabId": "tab1", + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 150.0, + "widgetName": "Canvas5", + "displayName": "Canvas", + "bottomRow": 300.0, + "topRow": 0.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 150.0, + "mobileRightColumn": 70.546875, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "isVisibleDownload": true, + "iconSVG": "/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg", + "topRow": 0.0, + "isSortable": true, + "type": "TABLE_WIDGET_V2", + "inlineEditingSaveOption": "ROW_LEVEL", + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "tableData" }, + { + "key": "primaryColumns.address.computedValue" + }, + { + "key": "primaryColumns.avatar.computedValue" + }, + { + "key": "primaryColumns.email.computedValue" + }, + { + "key": "primaryColumns.gender.computedValue" + }, + { + "key": "primaryColumns.id.computedValue" + }, + { + "key": "primaryColumns.name.computedValue" + }, + { + "key": "primaryColumns.status.computedValue" + } + ], + "needsHeightForContent": true, + "leftColumn": 2.0, + "delimiter": ",", + "defaultSelectedRowIndex": 0.0, + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisibleFilters": true, + "isVisible": true, + "enableClientSideSearch": true, + "version": 2.0, + "totalRecordsCount": 0.0, + "tags": ["Suggested", "Display"], + "isLoading": false, + "childStylesheet": { + "button": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "menuButton": { + "menuColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "iconButton": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "editActions": { + "saveButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "saveBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "discardButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "discardBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + }, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "columnUpdatedAt": 1.694586626019e12, + "defaultSelectedRowIndices": [0.0], + "mobileBottomRow": 28.0, + "widgetName": "Table1", + "defaultPageSize": 0.0, + "columnOrder": [ + "address", + "avatar", + "email", + "gender", + "id", + "name", + "status" + ], + "dynamicPropertyPathList": [], + "displayName": "Table", + "bottomRow": 28.0, + "columnWidthMap": {}, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 40.0, + "parentColumnSpace": 2.53509521484375, + "dynamicTriggerPathList": [], + "borderWidth": "1", + "primaryColumns": { + "address": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 0.0, + "width": 150.0, + "originalId": "address", + "id": "address", + "alias": "address", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "address", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"address\"]))}}", + "sticky": "", + "validation": {} + }, + "avatar": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 1.0, + "width": 150.0, + "originalId": "avatar", + "id": "avatar", + "alias": "avatar", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "avatar", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"avatar\"]))}}", + "sticky": "", + "validation": {} + }, + "email": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 2.0, + "width": 150.0, + "originalId": "email", + "id": "email", + "alias": "email", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "email", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"email\"]))}}", + "sticky": "", + "validation": {} + }, + "gender": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 3.0, + "width": 150.0, + "originalId": "gender", + "id": "gender", + "alias": "gender", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "gender", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"gender\"]))}}", + "sticky": "", + "validation": {} + }, + "id": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 4.0, + "width": 150.0, + "originalId": "id", + "id": "id", + "alias": "id", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "number", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "id", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"id\"]))}}", + "sticky": "", + "validation": {} + }, + "name": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 5.0, + "width": 150.0, + "originalId": "name", + "id": "name", + "alias": "name", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "name", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"name\"]))}}", + "sticky": "", + "validation": {} + }, + "status": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 6.0, + "width": 150.0, + "originalId": "status", + "id": "status", + "alias": "status", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "status", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"status\"]))}}", + "sticky": "", + "validation": {} + } + }, + "key": "3qwgjzmubu", + "canFreezeColumn": true, + "isDeprecated": false, + "rightColumn": 62.0, + "textSize": "0.875rem", + "widgetId": "b73obdenki", + "enableServerSideFiltering": false, + "minWidth": 450.0, + "tableData": "{{Api1.data}}", + "label": "Data", + "searchKey": "", + "parentId": "gq5pvoxzn5", + "renderMode": "CANVAS", + "mobileTopRow": 0.0, + "horizontalAlignment": "LEFT", + "isVisibleSearch": true, + "responsiveBehavior": "fill", + "mobileLeftColumn": 6.0, + "isVisiblePagination": true, + "verticalAlignment": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "tabName": "Tab 1", + "rightColumn": 70.546875, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "gq5pvoxzn5", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "g6cwwkiv7u", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + }, + { + "tabId": "tab2", + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 150.0, + "widgetName": "Canvas6", + "displayName": "Canvas", + "bottomRow": 300.0, + "topRow": 0.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 150.0, + "mobileRightColumn": 70.546875, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "tabName": "Tab 2", + "rightColumn": 70.546875, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "u6jv770pfr", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "g6cwwkiv7u", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": 1.0, + "key": "m440eh8y1m", + "backgroundColor": "#FFFFFF", + "isDeprecated": false, + "rightColumn": 62.0, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "g6cwwkiv7u", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "defaultTab": "Tab 1", + "shouldShowTabs": true, + "minWidth": 450.0, + "tabsObj": { + "tab1": { + "label": "Tab 1", + "id": "tab1", + "widgetId": "gq5pvoxzn5", + "isVisible": true, + "index": 0.0, + "positioning": "vertical" + }, + "tab2": { + "label": "Tab 2", + "id": "tab2", + "widgetId": "u6jv770pfr", + "isVisible": true, + "index": 1.0, + "positioning": "vertical" + } + }, + "isVisible": true, + "version": 3.0, + "parentId": "h6zbt0dppm", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4.0, + "responsiveBehavior": "fill", + "originalTopRow": 4.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 4.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 38.0, + "minDynamicHeight": 15.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton2", + "onClick": "{{Api1.run().then(() => {\n showAlert('Executed api!', '');\n});}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "dynamicPropertyPathList": [], + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "parentRowSpace": 10.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 6.0, + "animateLoading": true, + "parentColumnSpace": 6.408203125, + "dynamicTriggerPathList": [ + { "key": "onClick" } + ], + "leftColumn": 2.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 6.0, + "iconName": "play", + "widgetId": "u8032a0hmj", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "h6zbt0dppm", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 2.0, + "buttonVariant": "PRIMARY" + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 166.5, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "h6zbt0dppm", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "ux91zws0sp", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "flexVerticalAlignment": "start", + "key": "8nbypdc1zz", + "backgroundColor": "#FFFFFF", + "isDeprecated": false, + "rightColumn": 62.0, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ux91zws0sp", + "containerStyle": "card", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 64.0, + "responsiveBehavior": "fill", + "originalTopRow": 143.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 2.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 183.0, + "minDynamicHeight": 10.0 + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "59hk3a5cny", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "hz6llfbx4u", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 1900.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "hz6llfbx4u", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "originalTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 148.0, + "width": 456.0, + "minDynamicHeight": 10.0 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.a7b19dc8b31d68fcff57f1d2c0084a18.svg", + "labelText": "Label", + "topRow": 22.0, + "labelWidth": 5.0, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "defaultOptionValue": "GREEN", + "animateLoading": true, + "leftColumn": 7.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" } + ], + "placeholderText": "Select option", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Select"], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileBottomRow": 29.0, + "widgetName": "Select2", + "isFilterable": true, + "displayName": "Select", + "searchTags": ["dropdown"], + "bottomRow": 29.0, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 27.0, + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onOptionChange" }], + "labelPosition": "Top", + "sourceData": [ + { "name": "Blue", "code": "BLUE" }, + { "name": "Green", "code": "GREEN" }, + { "name": "Red", "code": "RED" } + ], + "key": "9go22qpbuu", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 27.0, + "widgetId": "w1w4pk9zzo", + "optionValue": "code", + "minWidth": 450.0, + "parentId": "0", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 22.0, + "optionLabel": "name", + "responsiveBehavior": "fill", + "mobileLeftColumn": 7.0, + "maxDynamicHeight": 9000.0, + "onOptionChange": "{{showModal('Modal2');}}", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal2", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas7", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 240.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton3", + "onClick": "{{closeModal('Modal2')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "hh5batn812", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "vuty12u6h2", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text5", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 9.0, + "bottomRow": 13.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 6.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Option changed!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 57.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ijf7l1u08i", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "vuty12u6h2", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "vuty12u6h2", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "lwewdg3z5m", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "lwewdg3z5m", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 262.0, + "minDynamicHeight": 24.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 17.0, + "pageSize": 3.0, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8.0, + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "currentItemsView" }, + { "key": "selectedItemView" }, + { "key": "triggeredItemView" }, + { "key": "primaryKeys" }, + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "leftColumn": 35.0, + "enhancements": true, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 400.0, + "widgetName": "Canvas8", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 400.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400.0, + "mobileRightColumn": 234.75, + "noPad": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12.0, + "widgetName": "Container3", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 0.0, + "bottomRow": 12.0, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "widgetName": "Canvas9", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 120.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Image3", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0.0, + "bottomRow": 8.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16.0, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { "key": "image" }, + { "key": "borderRadius" } + ], + "leftColumn": 0.0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "an3dz32jnz", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 16.0, + "objectFit": "cover", + "widgetId": "zsd3wguxr8", + "isVisible": true, + "version": 1.0, + "parentId": "5e7r8x4ogy", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "Text6", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 28.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "xxb9k9l324", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "5e7r8x4ogy", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Text7", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4.0, + "bottomRow": 8.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 24.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "jtxcmjnb72", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "5e7r8x4ogy", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "5e7r8x4ogy", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "kge1nh55vi", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "8nbypdc1zz", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64.0, + "dynamicHeight": "FIXED", + "widgetId": "kge1nh55vi", + "containerStyle": "card", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "isListItemContainer": true, + "parentId": "mvr73kk0mj", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": ["dynamicHeight"], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 10.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 234.75, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "mvr73kk0mj", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "b7fjdn1ail", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": ["Suggested", "Display"], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "mvr73kk0mj", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 57.0, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List2", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 57.0, + "parentRowSpace": 10.0, + "hideCard": false, + "templateBottomRow": 16.0, + "mobileRightColumn": 59.0, + "mainContainerId": "kge1nh55vi", + "primaryKeys": "{{List2.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onItemClick" }], + "gridType": "vertical", + "key": "mgbk7d2119", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 59.0, + "widgetId": "b7fjdn1ail", + "minWidth": 450.0, + "onItemClick": "{{showModal('Modal3');}}", + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 17.0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 35.0, + "selectedItemView": "{{{}}}" + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal3", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas10", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton4", + "onClick": "{{closeModal('Modal3')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "gp75kko147", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text8", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 8.0, + "bottomRow": 12.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 7.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "List Item Clicked!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 47.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ok3iewf220", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button2", + "onClick": "{{closeModal('Modal3')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 47.0, + "animateLoading": true, + "leftColumn": 31.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Close", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 47.0, + "isDefaultClickDisabled": true, + "widgetId": "ni3v3lt43c", + "buttonStyle": "PRIMARY", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 31.0, + "buttonVariant": "SECONDARY", + "placement": "CENTER" + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button3", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 63.0, + "animateLoading": true, + "leftColumn": 47.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Confirm", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "57uc88g7np", + "buttonStyle": "PRIMARY_BUTTON", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 47.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "lfj97zdxdw", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "ih3y0k7fhu", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ih3y0k7fhu", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 456.0, + "minDynamicHeight": 24.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "isVisibleDownload": true, + "iconSVG": "/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg", + "topRow": 34.0, + "isSortable": true, + "type": "TABLE_WIDGET_V2", + "inlineEditingSaveOption": "ROW_LEVEL", + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "tableData" }, + { "key": "primaryColumns.address.computedValue" }, + { "key": "primaryColumns.avatar.computedValue" }, + { "key": "primaryColumns.email.computedValue" }, + { "key": "primaryColumns.gender.computedValue" }, + { "key": "primaryColumns.id.computedValue" }, + { "key": "primaryColumns.name.computedValue" }, + { "key": "primaryColumns.status.computedValue" } + ], + "needsHeightForContent": true, + "leftColumn": 0.0, + "delimiter": ",", + "defaultSelectedRowIndex": 0.0, + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisibleFilters": true, + "isVisible": true, + "enableClientSideSearch": true, + "version": 2.0, + "totalRecordsCount": 0.0, + "tags": ["Suggested", "Display"], + "isLoading": false, + "onSearchTextChanged": "{{showModal('Modal4');}}", + "childStylesheet": { + "button": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "menuButton": { + "menuColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "iconButton": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "editActions": { + "saveButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "saveBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "discardButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "discardBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + }, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "columnUpdatedAt": 1.69459117549e12, + "defaultSelectedRowIndices": [0.0], + "mobileBottomRow": 62.0, + "widgetName": "Table2", + "defaultPageSize": 0.0, + "columnOrder": [ + "address", + "avatar", + "email", + "gender", + "id", + "name", + "status" + ], + "dynamicPropertyPathList": [], + "displayName": "Table", + "bottomRow": 62.0, + "columnWidthMap": {}, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 29.0, + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onSearchTextChanged" }], + "borderWidth": "1", + "primaryColumns": { + "address": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 0.0, + "width": 150.0, + "originalId": "address", + "id": "address", + "alias": "address", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "address", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"address\"]))}}", + "sticky": "", + "validation": {} + }, + "avatar": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 1.0, + "width": 150.0, + "originalId": "avatar", + "id": "avatar", + "alias": "avatar", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "avatar", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"avatar\"]))}}", + "sticky": "", + "validation": {} + }, + "email": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 2.0, + "width": 150.0, + "originalId": "email", + "id": "email", + "alias": "email", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "email", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"email\"]))}}", + "sticky": "", + "validation": {} + }, + "gender": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 3.0, + "width": 150.0, + "originalId": "gender", + "id": "gender", + "alias": "gender", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "gender", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"gender\"]))}}", + "sticky": "", + "validation": {} + }, + "id": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 4.0, + "width": 150.0, + "originalId": "id", + "id": "id", + "alias": "id", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "number", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "id", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"id\"]))}}", + "sticky": "", + "validation": {} + }, + "name": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 5.0, + "width": 150.0, + "originalId": "name", + "id": "name", + "alias": "name", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "name", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"name\"]))}}", + "sticky": "", + "validation": {} + }, + "status": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 6.0, + "width": 150.0, + "originalId": "status", + "id": "status", + "alias": "status", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "status", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"status\"]))}}", + "sticky": "", + "validation": {} + } + }, + "key": "3qwgjzmubu", + "canFreezeColumn": true, + "isDeprecated": false, + "rightColumn": 29.0, + "textSize": "0.875rem", + "widgetId": "wx0pg4tbs3", + "enableServerSideFiltering": false, + "minWidth": 450.0, + "tableData": "{{Api1.data}}", + "label": "Data", + "searchKey": "", + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 34.0, + "horizontalAlignment": "LEFT", + "isVisibleSearch": true, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0.0, + "isVisiblePagination": true, + "verticalAlignment": "CENTER" + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal4", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas11", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton5", + "onClick": "{{closeModal('Modal4')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "y581dyab2v", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text9", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 7.0, + "bottomRow": 11.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 7.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Table search value changed!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 47.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "0jm296331g", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button4", + "onClick": "{{closeModal('Modal4')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 47.0, + "animateLoading": true, + "leftColumn": 31.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Close", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 47.0, + "isDefaultClickDisabled": true, + "widgetId": "j1t93mn6cx", + "buttonStyle": "PRIMARY", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 31.0, + "buttonVariant": "SECONDARY", + "placement": "CENTER" + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button5", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 63.0, + "animateLoading": true, + "leftColumn": 47.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Confirm", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "uhwv2eik6s", + "buttonStyle": "PRIMARY_BUTTON", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 47.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "u5sz0sg17f", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "g5s1486z2m", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "g5s1486z2m", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 456.0, + "minDynamicHeight": 24.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "iconSVG": "/static/media/icon.46adf7030d667f0ad9002aa31f997573.svg", + "onSubmit": "{{showModal('Modal5');}}", + "topRow": 61.0, + "type": "JSON_FORM_WIDGET", + "animateLoading": true, + "leftColumn": 33.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "submitButtonStyles.buttonColor" }, + { "key": "submitButtonStyles.borderRadius" }, + { "key": "resetButtonStyles.buttonColor" }, + { "key": "resetButtonStyles.borderRadius" }, + { + "key": "schema.__root_schema__.children.name.defaultValue" + }, + { + "key": "schema.__root_schema__.children.name.accentColor" + }, + { + "key": "schema.__root_schema__.children.name.borderRadius" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.accentColor" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.borderRadius" + }, + { + "key": "schema.__root_schema__.children.employee_id.defaultValue" + }, + { + "key": "schema.__root_schema__.children.employee_id.accentColor" + }, + { + "key": "schema.__root_schema__.children.employee_id.borderRadius" + }, + { "key": "schema.__root_schema__.defaultValue" }, + { "key": "schema.__root_schema__.borderRadius" }, + { "key": "schema.__root_schema__.cellBorderRadius" } + ], + "showReset": true, + "dynamicHeight": "AUTO_HEIGHT", + "autoGenerateForm": true, + "resetButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "SECONDARY" + }, + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Layout"], + "isLoading": false, + "submitButtonLabel": "Submit", + "childStylesheet": { + "ARRAY": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "OBJECT": { + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "CHECKBOX": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + }, + "CURRENCY_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "DATEPICKER": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "EMAIL_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTISELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTILINE_TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PASSWORD_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PHONE_NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "RADIO_GROUP": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "SELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "SWITCH": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + } + }, + "disabledWhenInvalid": true, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 118.0, + "useSourceData": false, + "schema": { + "__root_schema__": { + "children": { + "name": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.name))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Text Input", + "sourceData": "John", + "isCustomField": false, + "accessor": "name", + "identifier": "name", + "position": 0.0, + "originalIdentifier": "name", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Name" + }, + "date_of_birth": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (moment(sourceData.date_of_birth, \"DD/MM/YYYY\").format(\"YYYY-MM-DDTHH:mm:ss.sssZ\")))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Datepicker", + "sourceData": "20/02/1990", + "isCustomField": false, + "accessor": "date_of_birth", + "identifier": "date_of_birth", + "position": 1.0, + "originalIdentifier": "date_of_birth", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "closeOnSelection": false, + "convertToISO": false, + "dateFormat": "DD/MM/YYYY", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "label": "Date Of Birth", + "maxDate": "2121-12-31T18:29:00.000Z", + "minDate": "1920-12-31T18:30:00.000Z", + "shortcuts": false, + "timePrecision": "minute", + "labelTextSize": "0.875rem" + }, + "employee_id": { + "children": {}, + "dataType": "number", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.employee_id))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Number Input", + "sourceData": 1001.0, + "isCustomField": false, + "accessor": "employee_id", + "identifier": "employee_id", + "position": 2.0, + "originalIdentifier": "employee_id", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Employee Id" + } + }, + "dataType": "object", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Object", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "isCustomField": false, + "accessor": "__root_schema__", + "identifier": "__root_schema__", + "position": -1.0, + "originalIdentifier": "__root_schema__", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "cellBorderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "cellBoxShadow": "none", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "" + } + }, + "mobileBottomRow": 102.0, + "widgetName": "JSONForm2", + "submitButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "PRIMARY" + }, + "dynamicPropertyPathList": [ + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + } + ], + "displayName": "JSON Form", + "bottomRow": 118.0, + "fieldLimitExceeded": false, + "parentRowSpace": 10.0, + "title": "Form", + "hideCard": false, + "mobileRightColumn": 58.0, + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onSubmit" }], + "borderWidth": "1", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "resetButtonLabel": "Reset", + "key": "csjsvvwmwh", + "backgroundColor": "#fff", + "isDeprecated": false, + "rightColumn": 58.0, + "widgetId": "ynk24jdjcq", + "minWidth": 450.0, + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 61.0, + "scrollContents": true, + "responsiveBehavior": "fill", + "fixedFooter": true, + "originalTopRow": 61.0, + "mobileLeftColumn": 33.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal5", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas12", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton6", + "onClick": "{{closeModal('Modal5')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "fyesozehw1", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text10", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 7.0, + "bottomRow": 11.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 6.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Form submitted!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 46.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "vdhzz04buu", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button6", + "onClick": "{{closeModal('Modal5')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 47.0, + "animateLoading": true, + "leftColumn": 31.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Close", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 47.0, + "isDefaultClickDisabled": true, + "widgetId": "b6us5yglbb", + "buttonStyle": "PRIMARY", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 31.0, + "buttonVariant": "SECONDARY", + "placement": "CENTER" + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button7", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 63.0, + "animateLoading": true, + "leftColumn": 47.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Confirm", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "zdvzbekkj8", + "buttonStyle": "PRIMARY_BUTTON", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 47.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "d0y05ie88b", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "m34ly0psqc", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "m34ly0psqc", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 456.0, + "minDynamicHeight": 24.0 + } + ] + }, + "layoutOnLoadActions": [ + [ + { + "id": "Page1_Api1", + "name": "Api1", + "confirmBeforeExecute": false, + "pluginType": "API", + "jsonPathKeys": [], + "timeoutInMillisecond": 10000.0 + } + ] + ], + "layoutOnLoadActionErrors": [], + "validOnPageLoadActions": true, + "id": "Page1", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "userPermissions": [], + "policies": [] + }, + "publishedPage": { + "name": "Page1", + "slug": "page1", + "layouts": [ + { + "viewMode": false, + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896.0, + "snapColumns": 64.0, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0.0, + "bottomRow": 1180.0, + "containerStyle": "none", + "snapRows": 124.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86.0, + "minHeight": 1292.0, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1.0, + "dynamicBindingPathList": [], + "leftColumn": 0.0, + "children": [ + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 12.0, + "widgetName": "Button1", + "onClick": "{{showModal('Modal1');}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 8.0, + "bottomRow": 12.0, + "parentRowSpace": 10.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 38.0, + "animateLoading": true, + "parentColumnSpace": 9.859375, + "dynamicTriggerPathList": [{ "key": "onClick" }], + "leftColumn": 22.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Submit", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 38.0, + "isDefaultClickDisabled": true, + "widgetId": "37aleq6qhk", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "0", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 8.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 22.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal1", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 190.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "minHeight": 1900.0, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas1", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 1900.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton1", + "onClick": "{{closeModal('Modal1')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "xvq75i05gs", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 1.0, + "bottomRow": 7.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 1.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Widgets Modal", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 41.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "vms8z4v4t9", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "originalTopRow": 1.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 5.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.f2c34197dbcf03595098986de898928f.svg", + "topRow": 7.0, + "labelWidth": 5.0, + "type": "INPUT_WIDGET_V2", + "animateLoading": true, + "resetOnSubmit": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" } + ], + "labelStyle": "", + "inputType": "TEXT", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": false, + "isVisible": true, + "version": 2.0, + "tags": ["Suggested", "Inputs"], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 12.0, + "mobileBottomRow": 13.0, + "widgetName": "Input1", + "displayName": "Input", + "searchTags": [ + "form", + "text input", + "number", + "textarea" + ], + "bottomRow": 14.0, + "parentRowSpace": 10.0, + "autoFocus": false, + "hideCard": false, + "mobileRightColumn": 23.0, + "parentColumnSpace": 6.9375, + "labelPosition": "Top", + "key": "m9ve3ppio8", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 24.0, + "widgetId": "qg5qem3xyp", + "minWidth": 450.0, + "label": "Label", + "parentId": "59hk3a5cny", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 6.0, + "responsiveBehavior": "fill", + "originalTopRow": 5.0, + "mobileLeftColumn": 3.0, + "maxDynamicHeight": 9000.0, + "iconAlign": "left", + "defaultText": "", + "minDynamicHeight": 4.0 + }, + { + "mobileBottomRow": 12.0, + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 7.0, + "bottomRow": 54.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 46.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [], + "leftColumn": 24.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{Table1.selectedRow}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 63.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ykifd3nlwx", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 8.0, + "responsiveBehavior": "fill", + "originalTopRow": 5.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 30.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 49.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.a7b19dc8b31d68fcff57f1d2c0084a18.svg", + "labelText": "Label", + "topRow": 55.0, + "labelWidth": 5.0, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "defaultOptionValue": "GREEN", + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "sourceData" } + ], + "placeholderText": "Select option", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Select"], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 57.0, + "mobileBottomRow": 20.0, + "widgetName": "Select1", + "isFilterable": true, + "dynamicPropertyPathList": [{ "key": "sourceData" }], + "displayName": "Select", + "searchTags": ["dropdown"], + "bottomRow": 62.0, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 21.0, + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [], + "labelPosition": "Top", + "sourceData": "[\n {\n \"name\": {{Input1.text}},\n \"code\": {{Input1.text}}\n },\n {\n \"name\": {{Input1.text+1}},\n \"code\": {{Input1.text+1}}\n },\n {\n \"name\": {{Input1.text+2}},\n \"code\": {{Input1.text+2}}\n }\n]", + "key": "9go22qpbuu", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 30.0, + "widgetId": "yg4ihellt5", + "optionValue": "code", + "minWidth": 450.0, + "parentId": "59hk3a5cny", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 13.0, + "optionLabel": "name", + "responsiveBehavior": "fill", + "originalTopRow": 50.0, + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 67.0, + "pageSize": 3.0, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8.0, + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "currentItemsView" }, + { "key": "selectedItemView" }, + { "key": "triggeredItemView" }, + { "key": "primaryKeys" }, + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "leftColumn": 0.0, + "enhancements": true, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 400.0, + "widgetName": "Canvas2", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 400.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400.0, + "mobileRightColumn": 166.5, + "noPad": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12.0, + "widgetName": "Container1", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 0.0, + "bottomRow": 12.0, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "widgetName": "Canvas3", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 120.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Image1", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0.0, + "bottomRow": 8.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16.0, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { "key": "borderRadius" } + ], + "leftColumn": 0.0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "an3dz32jnz", + "image": "https://jpeg.org/images/jpegsystems-home.jpg", + "isDeprecated": false, + "rightColumn": 16.0, + "objectFit": "cover", + "widgetId": "gn9wku1gs7", + "isVisible": true, + "version": 1.0, + "parentId": "rtjo8735m7", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "Text3", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 42.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "5dkd0u3zh7", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "rtjo8735m7", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Text4", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4.0, + "bottomRow": 8.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 40.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "684malsbtw", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "rtjo8735m7", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "rtjo8735m7", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "5m236c6iz7", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "8nbypdc1zz", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64.0, + "dynamicHeight": "FIXED", + "widgetId": "5m236c6iz7", + "containerStyle": "card", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "isListItemContainer": true, + "parentId": "cq5f7mkbyh", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": ["dynamicHeight"], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 10.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 166.5, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "cq5f7mkbyh", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "twucvyhokg", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": ["Suggested", "Display"], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "cq5f7mkbyh", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 102.0, + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 62.0, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List1", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 107.0, + "parentRowSpace": 10.0, + "hideCard": false, + "templateBottomRow": 16.0, + "mobileRightColumn": 24.0, + "mainContainerId": "5m236c6iz7", + "primaryKeys": "{{List1.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 6.9375, + "gridType": "vertical", + "key": "mgbk7d2119", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 62.0, + "widgetId": "twucvyhokg", + "minWidth": 450.0, + "parentId": "59hk3a5cny", + "renderMode": "CANVAS", + "mobileTopRow": 22.0, + "responsiveBehavior": "fill", + "originalTopRow": 62.0, + "mobileLeftColumn": 0.0, + "selectedItemView": "{{{}}}" + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "iconSVG": "/static/media/icon.46adf7030d667f0ad9002aa31f997573.svg", + "onSubmit": "{{showAlert('Form submitted!', 'success');}}", + "topRow": 107.0, + "type": "JSON_FORM_WIDGET", + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "submitButtonStyles.buttonColor" }, + { "key": "submitButtonStyles.borderRadius" }, + { "key": "resetButtonStyles.buttonColor" }, + { "key": "resetButtonStyles.borderRadius" }, + { + "key": "schema.__root_schema__.children.name.defaultValue" + }, + { + "key": "schema.__root_schema__.children.name.accentColor" + }, + { + "key": "schema.__root_schema__.children.name.borderRadius" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.accentColor" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.borderRadius" + }, + { + "key": "schema.__root_schema__.children.employee_id.defaultValue" + }, + { + "key": "schema.__root_schema__.children.employee_id.accentColor" + }, + { + "key": "schema.__root_schema__.children.employee_id.borderRadius" + }, + { "key": "schema.__root_schema__.defaultValue" }, + { "key": "schema.__root_schema__.borderRadius" }, + { "key": "schema.__root_schema__.cellBorderRadius" } + ], + "showReset": true, + "dynamicHeight": "FIXED", + "autoGenerateForm": true, + "resetButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "SECONDARY" + }, + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Layout"], + "isLoading": false, + "submitButtonLabel": "Submit", + "childStylesheet": { + "ARRAY": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "OBJECT": { + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "CHECKBOX": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + }, + "CURRENCY_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "DATEPICKER": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "EMAIL_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTISELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTILINE_TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PASSWORD_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PHONE_NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "RADIO_GROUP": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "SELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "SWITCH": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + } + }, + "disabledWhenInvalid": true, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 142.0, + "useSourceData": false, + "schema": { + "__root_schema__": { + "children": { + "name": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.name))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Text Input", + "sourceData": "John", + "isCustomField": false, + "accessor": "name", + "identifier": "name", + "position": 0.0, + "originalIdentifier": "name", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Name" + }, + "date_of_birth": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (moment(sourceData.date_of_birth, \"DD/MM/YYYY\").format(\"YYYY-MM-DDTHH:mm:ss.sssZ\")))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Datepicker", + "sourceData": "20/02/1990", + "isCustomField": false, + "accessor": "date_of_birth", + "identifier": "date_of_birth", + "position": 1.0, + "originalIdentifier": "date_of_birth", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "closeOnSelection": false, + "convertToISO": false, + "dateFormat": "DD/MM/YYYY", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "label": "Date Of Birth", + "maxDate": "2121-12-31T18:29:00.000Z", + "minDate": "1920-12-31T18:30:00.000Z", + "shortcuts": false, + "timePrecision": "minute", + "labelTextSize": "0.875rem" + }, + "employee_id": { + "children": {}, + "dataType": "number", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.employee_id))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Number Input", + "sourceData": 1001.0, + "isCustomField": false, + "accessor": "employee_id", + "identifier": "employee_id", + "position": 2.0, + "originalIdentifier": "employee_id", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Employee Id" + } + }, + "dataType": "object", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "fieldType": "Object", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "isCustomField": false, + "accessor": "__root_schema__", + "identifier": "__root_schema__", + "position": -1.0, + "originalIdentifier": "__root_schema__", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "boxShadow": "none", + "cellBorderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm1.sourceData, JSONForm1.formData, JSONForm1.fieldState)}}", + "cellBoxShadow": "none", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "" + } + }, + "mobileBottomRow": 54.0, + "widgetName": "JSONForm1", + "submitButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "PRIMARY" + }, + "dynamicPropertyPathList": [ + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + } + ], + "displayName": "JSON Form", + "bottomRow": 147.0, + "fieldLimitExceeded": false, + "parentRowSpace": 10.0, + "title": "Form", + "hideCard": false, + "mobileRightColumn": 42.0, + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [{ "key": "onSubmit" }], + "borderWidth": "1", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "resetButtonLabel": "Reset", + "key": "csjsvvwmwh", + "backgroundColor": "#fff", + "isDeprecated": false, + "rightColumn": 64.0, + "widgetId": "2pnkf5v8uj", + "minWidth": 450.0, + "parentId": "59hk3a5cny", + "renderMode": "CANVAS", + "mobileTopRow": 13.0, + "scrollContents": true, + "responsiveBehavior": "fill", + "fixedFooter": true, + "originalTopRow": 102.0, + "mobileLeftColumn": 17.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 67.0, + "widgetName": "Image2", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 54.0, + "bottomRow": 67.0, + "parentRowSpace": 10.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 50.0, + "animateLoading": true, + "parentColumnSpace": 6.9375, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "leftColumn": 32.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "defaultImage": "https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/5eeea355389655.59822ff824b72.gif", + "key": "an3dz32jnz", + "image": "", + "isDeprecated": false, + "rightColumn": 63.0, + "objectFit": "cover", + "widgetId": "h24avxj5g0", + "isVisible": true, + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 55.0, + "maxZoomLevel": 1.0, + "enableDownload": false, + "originalTopRow": 49.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 38.0, + "originalBottomRow": 62.0, + "enableRotation": false + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 74.0, + "widgetName": "Container2", + "borderColor": "#E0DEDE", + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 148.0, + "bottomRow": 188.0, + "parentRowSpace": 10.0, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 26.0, + "animateLoading": true, + "parentColumnSpace": 6.9375, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 100.0, + "widgetName": "Canvas4", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 400.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "minHeight": 100.0, + "mobileRightColumn": 166.5, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 19.0, + "widgetName": "Tabs1", + "borderColor": "#E0DEDE", + "isCanvas": true, + "displayName": "Tabs", + "iconSVG": "/static/media/icon.9e3d67c0af9c0bd092dc56240314e18a.svg", + "topRow": 4.0, + "bottomRow": 38.0, + "parentRowSpace": 10.0, + "type": "TABS_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 28.0, + "animateLoading": true, + "parentColumnSpace": 2.939453125, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "tabId": "tab1", + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 150.0, + "widgetName": "Canvas5", + "displayName": "Canvas", + "bottomRow": 300.0, + "topRow": 0.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 150.0, + "mobileRightColumn": 70.546875, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "isVisibleDownload": true, + "iconSVG": "/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg", + "topRow": 0.0, + "isSortable": true, + "type": "TABLE_WIDGET_V2", + "inlineEditingSaveOption": "ROW_LEVEL", + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "tableData" }, + { + "key": "primaryColumns.address.computedValue" + }, + { + "key": "primaryColumns.avatar.computedValue" + }, + { + "key": "primaryColumns.email.computedValue" + }, + { + "key": "primaryColumns.gender.computedValue" + }, + { + "key": "primaryColumns.id.computedValue" + }, + { + "key": "primaryColumns.name.computedValue" + }, + { + "key": "primaryColumns.status.computedValue" + } + ], + "needsHeightForContent": true, + "leftColumn": 2.0, + "delimiter": ",", + "defaultSelectedRowIndex": 0.0, + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisibleFilters": true, + "isVisible": true, + "enableClientSideSearch": true, + "version": 2.0, + "totalRecordsCount": 0.0, + "tags": ["Suggested", "Display"], + "isLoading": false, + "childStylesheet": { + "button": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "menuButton": { + "menuColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "iconButton": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "editActions": { + "saveButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "saveBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "discardButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "discardBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + }, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "columnUpdatedAt": 1.694586626019e12, + "defaultSelectedRowIndices": [0.0], + "mobileBottomRow": 28.0, + "widgetName": "Table1", + "defaultPageSize": 0.0, + "columnOrder": [ + "address", + "avatar", + "email", + "gender", + "id", + "name", + "status" + ], + "dynamicPropertyPathList": [], + "displayName": "Table", + "bottomRow": 28.0, + "columnWidthMap": {}, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 40.0, + "parentColumnSpace": 2.53509521484375, + "dynamicTriggerPathList": [], + "borderWidth": "1", + "primaryColumns": { + "address": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 0.0, + "width": 150.0, + "originalId": "address", + "id": "address", + "alias": "address", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "address", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"address\"]))}}", + "sticky": "", + "validation": {} + }, + "avatar": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 1.0, + "width": 150.0, + "originalId": "avatar", + "id": "avatar", + "alias": "avatar", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "avatar", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"avatar\"]))}}", + "sticky": "", + "validation": {} + }, + "email": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 2.0, + "width": 150.0, + "originalId": "email", + "id": "email", + "alias": "email", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "email", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"email\"]))}}", + "sticky": "", + "validation": {} + }, + "gender": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 3.0, + "width": 150.0, + "originalId": "gender", + "id": "gender", + "alias": "gender", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "gender", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"gender\"]))}}", + "sticky": "", + "validation": {} + }, + "id": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 4.0, + "width": 150.0, + "originalId": "id", + "id": "id", + "alias": "id", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "number", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "id", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"id\"]))}}", + "sticky": "", + "validation": {} + }, + "name": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 5.0, + "width": 150.0, + "originalId": "name", + "id": "name", + "alias": "name", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "name", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"name\"]))}}", + "sticky": "", + "validation": {} + }, + "status": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 6.0, + "width": 150.0, + "originalId": "status", + "id": "status", + "alias": "status", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "status", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"status\"]))}}", + "sticky": "", + "validation": {} + } + }, + "key": "3qwgjzmubu", + "canFreezeColumn": true, + "isDeprecated": false, + "rightColumn": 62.0, + "textSize": "0.875rem", + "widgetId": "b73obdenki", + "enableServerSideFiltering": false, + "minWidth": 450.0, + "tableData": "{{Api1.data}}", + "label": "Data", + "searchKey": "", + "parentId": "gq5pvoxzn5", + "renderMode": "CANVAS", + "mobileTopRow": 0.0, + "horizontalAlignment": "LEFT", + "isVisibleSearch": true, + "responsiveBehavior": "fill", + "mobileLeftColumn": 6.0, + "isVisiblePagination": true, + "verticalAlignment": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "tabName": "Tab 1", + "rightColumn": 70.546875, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "gq5pvoxzn5", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "g6cwwkiv7u", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + }, + { + "tabId": "tab2", + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 150.0, + "widgetName": "Canvas6", + "displayName": "Canvas", + "bottomRow": 300.0, + "topRow": 0.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 150.0, + "mobileRightColumn": 70.546875, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "tabName": "Tab 2", + "rightColumn": 70.546875, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "u6jv770pfr", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "g6cwwkiv7u", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": 1.0, + "key": "m440eh8y1m", + "backgroundColor": "#FFFFFF", + "isDeprecated": false, + "rightColumn": 62.0, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "g6cwwkiv7u", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "defaultTab": "Tab 1", + "shouldShowTabs": true, + "minWidth": 450.0, + "tabsObj": { + "tab1": { + "label": "Tab 1", + "id": "tab1", + "widgetId": "gq5pvoxzn5", + "isVisible": true, + "index": 0.0, + "positioning": "vertical" + }, + "tab2": { + "label": "Tab 2", + "id": "tab2", + "widgetId": "u6jv770pfr", + "isVisible": true, + "index": 1.0, + "positioning": "vertical" + } + }, + "isVisible": true, + "version": 3.0, + "parentId": "h6zbt0dppm", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4.0, + "responsiveBehavior": "fill", + "originalTopRow": 4.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 4.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 38.0, + "minDynamicHeight": 15.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton2", + "onClick": "{{Api1.run().then(() => {\n showAlert('Executed api!', '');\n});}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "dynamicPropertyPathList": [], + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "parentRowSpace": 10.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 6.0, + "animateLoading": true, + "parentColumnSpace": 6.408203125, + "dynamicTriggerPathList": [ + { "key": "onClick" } + ], + "leftColumn": 2.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 6.0, + "iconName": "play", + "widgetId": "u8032a0hmj", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "h6zbt0dppm", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 2.0, + "buttonVariant": "PRIMARY" + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 166.5, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "h6zbt0dppm", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "ux91zws0sp", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "flexVerticalAlignment": "start", + "key": "8nbypdc1zz", + "backgroundColor": "#FFFFFF", + "isDeprecated": false, + "rightColumn": 62.0, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ux91zws0sp", + "containerStyle": "card", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "59hk3a5cny", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 64.0, + "responsiveBehavior": "fill", + "originalTopRow": 143.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 2.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 183.0, + "minDynamicHeight": 10.0 + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "59hk3a5cny", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "hz6llfbx4u", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 1900.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "hz6llfbx4u", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "originalTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 148.0, + "width": 456.0, + "minDynamicHeight": 10.0 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.a7b19dc8b31d68fcff57f1d2c0084a18.svg", + "labelText": "Label", + "topRow": 22.0, + "labelWidth": 5.0, + "type": "SELECT_WIDGET", + "serverSideFiltering": false, + "defaultOptionValue": "GREEN", + "animateLoading": true, + "leftColumn": 7.0, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" } + ], + "placeholderText": "Select option", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Select"], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileBottomRow": 29.0, + "widgetName": "Select2", + "isFilterable": true, + "displayName": "Select", + "searchTags": ["dropdown"], + "bottomRow": 29.0, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 27.0, + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onOptionChange" }], + "labelPosition": "Top", + "sourceData": [ + { "name": "Blue", "code": "BLUE" }, + { "name": "Green", "code": "GREEN" }, + { "name": "Red", "code": "RED" } + ], + "key": "9go22qpbuu", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 27.0, + "widgetId": "w1w4pk9zzo", + "optionValue": "code", + "minWidth": 450.0, + "parentId": "0", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 22.0, + "optionLabel": "name", + "responsiveBehavior": "fill", + "mobileLeftColumn": 7.0, + "maxDynamicHeight": 9000.0, + "onOptionChange": "{{showModal('Modal2');}}", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal2", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas7", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 240.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton3", + "onClick": "{{closeModal('Modal2')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "hh5batn812", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "vuty12u6h2", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text5", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 9.0, + "bottomRow": 13.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 6.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Option changed!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 57.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ijf7l1u08i", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "vuty12u6h2", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "vuty12u6h2", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "lwewdg3z5m", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "lwewdg3z5m", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 262.0, + "minDynamicHeight": 24.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "requiresFlatWidgetChildren": true, + "isCanvas": true, + "iconSVG": "/static/media/icon.5c9511142b3624c7491c5442e8ccd0ef.svg", + "topRow": 17.0, + "pageSize": 3.0, + "type": "LIST_WIDGET_V2", + "itemSpacing": 8.0, + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "currentItemsView" }, + { "key": "selectedItemView" }, + { "key": "triggeredItemView" }, + { "key": "primaryKeys" }, + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "leftColumn": 35.0, + "enhancements": true, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 400.0, + "widgetName": "Canvas8", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 400.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "dropDisabled": true, + "openParentPropertyPane": true, + "minHeight": 400.0, + "mobileRightColumn": 234.75, + "noPad": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 12.0, + "widgetName": "Container3", + "borderColor": "#E0DEDE", + "disallowCopy": true, + "isCanvas": true, + "displayName": "Container", + "iconSVG": "/static/media/icon.daebf68875b6c8e909e9e8ac8bee0c02.svg", + "searchTags": ["div", "parent", "group"], + "topRow": 0.0, + "bottomRow": 12.0, + "dragDisabled": true, + "type": "CONTAINER_WIDGET", + "hideCard": false, + "shouldScrollContents": false, + "isDeletable": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "widgetName": "Canvas9", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 120.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": false, + "hideCard": true, + "useAutoLayout": false, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Image3", + "displayName": "Image", + "iconSVG": "/static/media/icon.69b0f0dd810281fbd6e34fc2c3f39344.svg", + "topRow": 0.0, + "bottomRow": 8.0, + "type": "IMAGE_WIDGET", + "hideCard": false, + "mobileRightColumn": 16.0, + "animateLoading": true, + "dynamicTriggerPathList": [], + "imageShape": "RECTANGLE", + "dynamicBindingPathList": [ + { "key": "image" }, + { "key": "borderRadius" } + ], + "leftColumn": 0.0, + "defaultImage": "https://assets.appsmith.com/widgets/default.png", + "key": "an3dz32jnz", + "image": "{{currentItem.img}}", + "isDeprecated": false, + "rightColumn": 16.0, + "objectFit": "cover", + "widgetId": "zsd3wguxr8", + "isVisible": true, + "version": 1.0, + "parentId": "5e7r8x4ogy", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "maxZoomLevel": 1.0, + "enableDownload": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "enableRotation": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "Text6", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 28.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.name}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 28.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "xxb9k9l324", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "5e7r8x4ogy", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "HEADING", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 8.0, + "widgetName": "Text7", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 4.0, + "bottomRow": 8.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 24.0, + "animateLoading": true, + "overflow": "NONE", + "dynamicTriggerPathList": [], + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicBindingPathList": [ + { "key": "text" }, + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "leftColumn": 16.0, + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{currentItem.id}}", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 24.0, + "textAlign": "LEFT", + "dynamicHeight": "FIXED", + "widgetId": "jtxcmjnb72", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "5e7r8x4ogy", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 4.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 16.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "textStyle": "BODY", + "minDynamicHeight": 4.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "5e7r8x4ogy", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "kge1nh55vi", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "borderWidth": "1", + "positioning": "fixed", + "flexVerticalAlignment": "start", + "key": "8nbypdc1zz", + "backgroundColor": "white", + "isDeprecated": false, + "rightColumn": 64.0, + "dynamicHeight": "FIXED", + "widgetId": "kge1nh55vi", + "containerStyle": "card", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "isListItemContainer": true, + "parentId": "mvr73kk0mj", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "noContainerOffset": true, + "disabledWidgetFeatures": ["dynamicHeight"], + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 10.0 + } + ], + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 234.75, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "mvr73kk0mj", + "containerStyle": "none", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "b7fjdn1ail", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "itemBackgroundColor": "#FFFFFF", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "tags": ["Suggested", "Display"], + "hasMetaWidgets": true, + "isLoading": false, + "mainCanvasId": "mvr73kk0mj", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "additionalStaticProps": [ + "level", + "levelData", + "prefixMetaWidgetId", + "metaWidgetId" + ], + "mobileBottomRow": 57.0, + "currentItemsView": "{{[]}}", + "triggeredItemView": "{{{}}}", + "widgetName": "List2", + "listData": [ + { + "id": "001", + "name": "Blue", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "002", + "name": "Green", + "img": "https://assets.appsmith.com/widgets/default.png" + }, + { + "id": "003", + "name": "Red", + "img": "https://assets.appsmith.com/widgets/default.png" + } + ], + "displayName": "List", + "bottomRow": 57.0, + "parentRowSpace": 10.0, + "hideCard": false, + "templateBottomRow": 16.0, + "mobileRightColumn": 59.0, + "mainContainerId": "kge1nh55vi", + "primaryKeys": "{{List2.listData.map((currentItem, currentIndex) => currentItem[\"id\"] )}}", + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onItemClick" }], + "gridType": "vertical", + "key": "mgbk7d2119", + "backgroundColor": "transparent", + "isDeprecated": false, + "rightColumn": 59.0, + "widgetId": "b7fjdn1ail", + "minWidth": 450.0, + "onItemClick": "{{showModal('Modal3');}}", + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 17.0, + "responsiveBehavior": "fill", + "mobileLeftColumn": 35.0, + "selectedItemView": "{{{}}}" + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal3", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas10", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton4", + "onClick": "{{closeModal('Modal3')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "gp75kko147", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text8", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 8.0, + "bottomRow": 12.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 7.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "List Item Clicked!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 47.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ok3iewf220", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button2", + "onClick": "{{closeModal('Modal3')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 47.0, + "animateLoading": true, + "leftColumn": 31.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Close", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 47.0, + "isDefaultClickDisabled": true, + "widgetId": "ni3v3lt43c", + "buttonStyle": "PRIMARY", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 31.0, + "buttonVariant": "SECONDARY", + "placement": "CENTER" + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button3", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 63.0, + "animateLoading": true, + "leftColumn": 47.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Confirm", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "57uc88g7np", + "buttonStyle": "PRIMARY_BUTTON", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "lfj97zdxdw", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 47.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "lfj97zdxdw", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "ih3y0k7fhu", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "ih3y0k7fhu", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 456.0, + "minDynamicHeight": 24.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "isVisibleDownload": true, + "iconSVG": "/static/media/icon.e6911f8bb94dc6c4a102a74740c41763.svg", + "topRow": 34.0, + "isSortable": true, + "type": "TABLE_WIDGET_V2", + "inlineEditingSaveOption": "ROW_LEVEL", + "animateLoading": true, + "dynamicBindingPathList": [ + { "key": "accentColor" }, + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "tableData" }, + { "key": "primaryColumns.address.computedValue" }, + { "key": "primaryColumns.avatar.computedValue" }, + { "key": "primaryColumns.email.computedValue" }, + { "key": "primaryColumns.gender.computedValue" }, + { "key": "primaryColumns.id.computedValue" }, + { "key": "primaryColumns.name.computedValue" }, + { "key": "primaryColumns.status.computedValue" } + ], + "needsHeightForContent": true, + "leftColumn": 0.0, + "delimiter": ",", + "defaultSelectedRowIndex": 0.0, + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisibleFilters": true, + "isVisible": true, + "enableClientSideSearch": true, + "version": 2.0, + "totalRecordsCount": 0.0, + "tags": ["Suggested", "Display"], + "isLoading": false, + "onSearchTextChanged": "{{showModal('Modal4');}}", + "childStylesheet": { + "button": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "menuButton": { + "menuColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "iconButton": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "editActions": { + "saveButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "saveBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "discardButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "discardBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + }, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "columnUpdatedAt": 1.69459117549e12, + "defaultSelectedRowIndices": [0.0], + "mobileBottomRow": 62.0, + "widgetName": "Table2", + "defaultPageSize": 0.0, + "columnOrder": [ + "address", + "avatar", + "email", + "gender", + "id", + "name", + "status" + ], + "dynamicPropertyPathList": [], + "displayName": "Table", + "bottomRow": 62.0, + "columnWidthMap": {}, + "parentRowSpace": 10.0, + "hideCard": false, + "mobileRightColumn": 29.0, + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onSearchTextChanged" }], + "borderWidth": "1", + "primaryColumns": { + "address": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 0.0, + "width": 150.0, + "originalId": "address", + "id": "address", + "alias": "address", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "address", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"address\"]))}}", + "sticky": "", + "validation": {} + }, + "avatar": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 1.0, + "width": 150.0, + "originalId": "avatar", + "id": "avatar", + "alias": "avatar", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "avatar", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"avatar\"]))}}", + "sticky": "", + "validation": {} + }, + "email": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 2.0, + "width": 150.0, + "originalId": "email", + "id": "email", + "alias": "email", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "email", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"email\"]))}}", + "sticky": "", + "validation": {} + }, + "gender": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 3.0, + "width": 150.0, + "originalId": "gender", + "id": "gender", + "alias": "gender", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "gender", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"gender\"]))}}", + "sticky": "", + "validation": {} + }, + "id": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 4.0, + "width": 150.0, + "originalId": "id", + "id": "id", + "alias": "id", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "number", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "id", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"id\"]))}}", + "sticky": "", + "validation": {} + }, + "name": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 5.0, + "width": 150.0, + "originalId": "name", + "id": "name", + "alias": "name", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "name", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"name\"]))}}", + "sticky": "", + "validation": {} + }, + "status": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 6.0, + "width": 150.0, + "originalId": "status", + "id": "status", + "alias": "status", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "status", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table2.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"status\"]))}}", + "sticky": "", + "validation": {} + } + }, + "key": "3qwgjzmubu", + "canFreezeColumn": true, + "isDeprecated": false, + "rightColumn": 29.0, + "textSize": "0.875rem", + "widgetId": "wx0pg4tbs3", + "enableServerSideFiltering": false, + "minWidth": 450.0, + "tableData": "{{Api1.data}}", + "label": "Data", + "searchKey": "", + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 34.0, + "horizontalAlignment": "LEFT", + "isVisibleSearch": true, + "responsiveBehavior": "fill", + "mobileLeftColumn": 0.0, + "isVisiblePagination": true, + "verticalAlignment": "CENTER" + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal4", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas11", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton5", + "onClick": "{{closeModal('Modal4')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "y581dyab2v", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text9", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 7.0, + "bottomRow": 11.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 7.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Table search value changed!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 47.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "0jm296331g", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button4", + "onClick": "{{closeModal('Modal4')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 47.0, + "animateLoading": true, + "leftColumn": 31.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Close", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 47.0, + "isDefaultClickDisabled": true, + "widgetId": "j1t93mn6cx", + "buttonStyle": "PRIMARY", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 31.0, + "buttonVariant": "SECONDARY", + "placement": "CENTER" + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button5", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 63.0, + "animateLoading": true, + "leftColumn": 47.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Confirm", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "uhwv2eik6s", + "buttonStyle": "PRIMARY_BUTTON", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "u5sz0sg17f", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 47.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "u5sz0sg17f", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "g5s1486z2m", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "g5s1486z2m", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 456.0, + "minDynamicHeight": 24.0 + }, + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "iconSVG": "/static/media/icon.46adf7030d667f0ad9002aa31f997573.svg", + "onSubmit": "{{showModal('Modal5');}}", + "topRow": 61.0, + "type": "JSON_FORM_WIDGET", + "animateLoading": true, + "leftColumn": 33.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" }, + { "key": "submitButtonStyles.buttonColor" }, + { "key": "submitButtonStyles.borderRadius" }, + { "key": "resetButtonStyles.buttonColor" }, + { "key": "resetButtonStyles.borderRadius" }, + { + "key": "schema.__root_schema__.children.name.defaultValue" + }, + { + "key": "schema.__root_schema__.children.name.accentColor" + }, + { + "key": "schema.__root_schema__.children.name.borderRadius" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.accentColor" + }, + { + "key": "schema.__root_schema__.children.date_of_birth.borderRadius" + }, + { + "key": "schema.__root_schema__.children.employee_id.defaultValue" + }, + { + "key": "schema.__root_schema__.children.employee_id.accentColor" + }, + { + "key": "schema.__root_schema__.children.employee_id.borderRadius" + }, + { "key": "schema.__root_schema__.defaultValue" }, + { "key": "schema.__root_schema__.borderRadius" }, + { "key": "schema.__root_schema__.cellBorderRadius" } + ], + "showReset": true, + "dynamicHeight": "AUTO_HEIGHT", + "autoGenerateForm": true, + "resetButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "SECONDARY" + }, + "isVisible": true, + "version": 1.0, + "tags": ["Suggested", "Layout"], + "isLoading": false, + "submitButtonLabel": "Submit", + "childStylesheet": { + "ARRAY": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "OBJECT": { + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "cellBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "cellBoxShadow": "none" + }, + "CHECKBOX": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + }, + "CURRENCY_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "DATEPICKER": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "EMAIL_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTISELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "MULTILINE_TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PASSWORD_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "PHONE_NUMBER_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "RADIO_GROUP": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "SELECT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "SWITCH": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "boxShadow": "none" + }, + "TEXT_INPUT": { + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + } + }, + "disabledWhenInvalid": true, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 118.0, + "useSourceData": false, + "schema": { + "__root_schema__": { + "children": { + "name": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.name))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Text Input", + "sourceData": "John", + "isCustomField": false, + "accessor": "name", + "identifier": "name", + "position": 0.0, + "originalIdentifier": "name", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Name" + }, + "date_of_birth": { + "children": {}, + "dataType": "string", + "defaultValue": "{{((sourceData, formData, fieldState) => (moment(sourceData.date_of_birth, \"DD/MM/YYYY\").format(\"YYYY-MM-DDTHH:mm:ss.sssZ\")))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Datepicker", + "sourceData": "20/02/1990", + "isCustomField": false, + "accessor": "date_of_birth", + "identifier": "date_of_birth", + "position": 1.0, + "originalIdentifier": "date_of_birth", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "closeOnSelection": false, + "convertToISO": false, + "dateFormat": "DD/MM/YYYY", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "label": "Date Of Birth", + "maxDate": "2121-12-31T18:29:00.000Z", + "minDate": "1920-12-31T18:30:00.000Z", + "shortcuts": false, + "timePrecision": "minute", + "labelTextSize": "0.875rem" + }, + "employee_id": { + "children": {}, + "dataType": "number", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData.employee_id))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Number Input", + "sourceData": 1001.0, + "isCustomField": false, + "accessor": "employee_id", + "identifier": "employee_id", + "position": 2.0, + "originalIdentifier": "employee_id", + "accentColor": "{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "iconAlign": "left", + "isDisabled": false, + "isRequired": false, + "isSpellCheck": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "Employee Id" + } + }, + "dataType": "object", + "defaultValue": "{{((sourceData, formData, fieldState) => (sourceData))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "fieldType": "Object", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "isCustomField": false, + "accessor": "__root_schema__", + "identifier": "__root_schema__", + "position": -1.0, + "originalIdentifier": "__root_schema__", + "borderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "boxShadow": "none", + "cellBorderRadius": "{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(JSONForm2.sourceData, JSONForm2.formData, JSONForm2.fieldState)}}", + "cellBoxShadow": "none", + "isDisabled": false, + "isRequired": false, + "isVisible": true, + "labelTextSize": "0.875rem", + "label": "" + } + }, + "mobileBottomRow": 102.0, + "widgetName": "JSONForm2", + "submitButtonStyles": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none", + "buttonVariant": "PRIMARY" + }, + "dynamicPropertyPathList": [ + { + "key": "schema.__root_schema__.children.date_of_birth.defaultValue" + } + ], + "displayName": "JSON Form", + "bottomRow": 118.0, + "fieldLimitExceeded": false, + "parentRowSpace": 10.0, + "title": "Form", + "hideCard": false, + "mobileRightColumn": 58.0, + "parentColumnSpace": 9.78125, + "dynamicTriggerPathList": [{ "key": "onSubmit" }], + "borderWidth": "1", + "sourceData": { + "name": "John", + "date_of_birth": "20/02/1990", + "employee_id": 1001.0 + }, + "resetButtonLabel": "Reset", + "key": "csjsvvwmwh", + "backgroundColor": "#fff", + "isDeprecated": false, + "rightColumn": 58.0, + "widgetId": "ynk24jdjcq", + "minWidth": 450.0, + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 61.0, + "scrollContents": true, + "responsiveBehavior": "fill", + "fixedFooter": true, + "originalTopRow": 61.0, + "mobileLeftColumn": 33.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "mobileBottomRow": 0.0, + "widgetName": "Modal5", + "isCanvas": true, + "displayName": "Modal", + "iconSVG": "/static/media/icon.b374721fa8e1aeab7cf326c2d865506f.svg", + "searchTags": ["dialog", "popup", "notification"], + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "MODAL_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 0.0, + "animateLoading": true, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 0.0, + "widgetName": "Canvas12", + "displayName": "Canvas", + "topRow": 0.0, + "bottomRow": 240.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 0.0, + "mobileRightColumn": 0.0, + "parentColumnSpace": 1.0, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "children": [ + { + "boxShadow": "none", + "mobileBottomRow": 4.0, + "widgetName": "IconButton6", + "onClick": "{{closeModal('Modal5')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Icon button", + "iconSVG": "/static/media/icon.b08054586989b185a0801e9a34f8ad49.svg", + "searchTags": ["click", "submit"], + "topRow": 0.0, + "bottomRow": 4.0, + "type": "ICON_BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 64.0, + "animateLoading": true, + "leftColumn": 58.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "iconSize": 24.0, + "isDisabled": false, + "key": "rzx1ugxw80", + "isDeprecated": false, + "rightColumn": 64.0, + "iconName": "cross", + "widgetId": "fyesozehw1", + "minWidth": 50.0, + "isVisible": true, + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 58.0, + "buttonVariant": "TERTIARY" + }, + { + "mobileBottomRow": 5.0, + "widgetName": "Text10", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": ["typography", "paragraph", "label"], + "topRow": 7.0, + "bottomRow": 11.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 41.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "dynamicTriggerPathList": [], + "leftColumn": 6.0, + "dynamicBindingPathList": [ + { "key": "truncateButtonColor" }, + { "key": "fontFamily" }, + { "key": "borderRadius" } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Form submitted!", + "key": "eggq940xcg", + "isDeprecated": false, + "rightColumn": 46.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "vdhzz04buu", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Suggested", "Content"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 1.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1.25rem", + "minDynamicHeight": 4.0 + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button6", + "onClick": "{{closeModal('Modal5')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 47.0, + "animateLoading": true, + "leftColumn": 31.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Close", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 47.0, + "isDefaultClickDisabled": true, + "widgetId": "b6us5yglbb", + "buttonStyle": "PRIMARY", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 31.0, + "buttonVariant": "SECONDARY", + "placement": "CENTER" + }, + { + "resetFormOnClick": false, + "boxShadow": "none", + "mobileBottomRow": 22.0, + "widgetName": "Button7", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "displayName": "Button", + "iconSVG": "/static/media/icon.05d209fafeb13a8569e3b4e97069d9ee.svg", + "searchTags": ["click", "submit"], + "topRow": 18.0, + "bottomRow": 22.0, + "type": "BUTTON_WIDGET", + "hideCard": false, + "mobileRightColumn": 63.0, + "animateLoading": true, + "leftColumn": 47.0, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Confirm", + "isDisabled": false, + "key": "psr2q2qnuk", + "isDeprecated": false, + "rightColumn": 63.0, + "isDefaultClickDisabled": true, + "widgetId": "zdvzbekkj8", + "buttonStyle": "PRIMARY_BUTTON", + "minWidth": 120.0, + "isVisible": true, + "recaptchaType": "V3", + "version": 1.0, + "parentId": "d0y05ie88b", + "tags": ["Buttons"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 18.0, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 47.0, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ], + "isDisabled": false, + "key": "gmdsbkf4kj", + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "d0y05ie88b", + "minWidth": 450.0, + "isVisible": true, + "version": 1.0, + "parentId": "m34ly0psqc", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "minDynamicHeight": 4.0, + "flexLayers": [] + } + ], + "key": "ole7lkmkv0", + "height": 240.0, + "isDeprecated": false, + "rightColumn": 0.0, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "m34ly0psqc", + "canOutsideClickClose": true, + "canEscapeKeyClose": true, + "version": 2.0, + "parentId": "0", + "tags": ["Layout"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "width": 456.0, + "minDynamicHeight": 24.0 + } + ] + }, + "layoutOnLoadActions": [ + [ + { + "id": "Page1_Api1", + "name": "Api1", + "confirmBeforeExecute": false, + "pluginType": "API", + "jsonPathKeys": [], + "timeoutInMillisecond": 10000.0 + } + ] + ], + "layoutOnLoadActionErrors": [], + "validOnPageLoadActions": true, + "id": "Page1", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "userPermissions": [], + "policies": [] + }, + "deleted": false, + "gitSyncId": "65015519504ba7054aa92432_65015519504ba7054aa92434" + } + ], + "actionList": [ + { + "pluginType": "API", + "pluginId": "restapi-plugin", + "unpublishedAction": { + "name": "Api1", + "datasource": { + "name": "DEFAULT_REST_DATASOURCE", + "pluginId": "restapi-plugin", + "datasourceConfiguration": { + "url": "http://host.docker.internal:5001" + }, + "invalids": [], + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Page1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "path": "/v1/mock-api", + "headers": [], + "encodeParamsToggle": true, + "queryParameters": [{ "key": "records", "value": "10" }], + "bodyFormData": [], + "httpMethod": "GET", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }], + "formData": { "apiContentType": "none" } + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2023-09-13T06:29:30Z" + }, + "publishedAction": { + "name": "Api1", + "datasource": { + "name": "DEFAULT_REST_DATASOURCE", + "pluginId": "restapi-plugin", + "datasourceConfiguration": { + "url": "http://host.docker.internal:5001" + }, + "invalids": [], + "messages": [], + "isAutoGenerated": false, + "deleted": false, + "policies": [], + "userPermissions": [] + }, + "pageId": "Page1", + "actionConfiguration": { + "timeoutInMillisecond": 10000.0, + "paginationType": "NONE", + "path": "/v1/mock-api", + "headers": [], + "encodeParamsToggle": true, + "queryParameters": [{ "key": "records", "value": "10" }], + "bodyFormData": [], + "httpMethod": "GET", + "selfReferencingDataPaths": [], + "pluginSpecifiedTemplates": [{ "value": true }], + "formData": { "apiContentType": "none" } + }, + "executeOnLoad": true, + "dynamicBindingPathList": [], + "isValid": true, + "invalids": [], + "messages": [], + "jsonPathKeys": [], + "userSetOnLoad": false, + "confirmBeforeExecute": false, + "policies": [], + "userPermissions": [], + "createdAt": "2023-09-13T06:29:30Z" + }, + "id": "Page1_Api1", + "deleted": false, + "gitSyncId": "65015519504ba7054aa92432_650156ca504ba7054aa92437" + } + ], + "actionCollectionList": [], + "updatedResources": { + "customJSLibList": [], + "actionList": ["Api1##ENTITY_SEPARATOR##Page1"], + "pageList": ["Page1"], + "actionCollectionList": [] + }, + "editModeTheme": { + "name": "Default", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false + }, + "publishedTheme": { + "name": "Default", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false + } +} diff --git a/app/client/cypress/fixtures/multiTreeSelectDsl.json b/app/client/cypress/fixtures/multiTreeSelectDsl.json new file mode 100644 index 0000000000..b9c0e7c6aa --- /dev/null +++ b/app/client/cypress/fixtures/multiTreeSelectDsl.json @@ -0,0 +1,217 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 490, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.3167ea09b141a0db57f2a78cfc022004.svg", + "labelText": "Label", + "topRow": 25, + "labelWidth": 5, + "type": "MULTI_SELECT_TREE_WIDGET", + "mode": "SHOW_ALL", + "defaultOptionValue": "[\n \"GREEN\"\n]", + "animateLoading": true, + "leftColumn": 2, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + } + ], + "options": "[\n {\n \"label\": \"Blue\",\n \"value\": \"BLUE\",\n \"children\": [\n {\n \"label\": \"Dark Blue\",\n \"value\": \"DARK BLUE\"\n },\n {\n \"label\": \"Light Blue\",\n \"value\": \"LIGHT BLUE\"\n }\n ]\n },\n {\n \"label\": \"Green\",\n \"value\": \"GREEN\"\n },\n {\n \"label\": \"Red\",\n \"value\": \"RED\"\n }\n]", + "placeholderText": "Select option(s)", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "version": 1, + "expandAll": false, + "tags": [ + "Select" + ], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileBottomRow": 35, + "widgetName": "MultiTreeSelect1", + "displayName": "Multi TreeSelect", + "searchTags": [ + "dropdown", + "multiselecttree" + ], + "bottomRow": 36, + "parentRowSpace": 10, + "hideCard": false, + "mobileRightColumn": 38, + "parentColumnSpace": 6.15625, + "dynamicTriggerPathList": [], + "labelPosition": "Top", + "key": "bbhhwszfum", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 61, + "widgetId": "ok7riyytar", + "minWidth": 450, + "parentId": "0", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 28, + "responsiveBehavior": "fill", + "mobileLeftColumn": 18, + "maxDynamicHeight": 9000, + "allowClear": false, + "minDynamicHeight": 4 + }, + { + "boxShadow": "none", + "iconSVG": "/static/media/icon.950aa351208d9d9b2a695b3881ec3779.svg", + "topRow": 42, + "defaultCurrencyCode": "INR", + "labelWidth": 5, + "type": "CURRENCY_INPUT_WIDGET", + "animateLoading": true, + "resetOnSubmit": true, + "leftColumn": 9, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + } + ], + "labelStyle": "", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": false, + "isVisible": true, + "allowCurrencyChange": false, + "version": 1, + "tags": [ + "Inputs" + ], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileBottomRow": 50, + "widgetName": "CurrencyInput1", + "displayName": "Currency Input", + "searchTags": [ + "amount", + "total" + ], + "bottomRow": 49, + "parentRowSpace": 10, + "autoFocus": false, + "hideCard": false, + "mobileRightColumn": 41, + "parentColumnSpace": 10.078125, + "labelPosition": "Top", + "key": "7ohqpj6gcx", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 29, + "widgetId": "63ph31tykz", + "minWidth": 450, + "label": "Label", + "parentId": "0", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 43, + "responsiveBehavior": "fill", + "mobileLeftColumn": 21, + "maxDynamicHeight": 9000, + "decimals": 0, + "iconAlign": "left", + "defaultText": "", + "minDynamicHeight": 4 + }, + { + "mobileBottomRow": 48, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 44, + "bottomRow": 48, + "parentRowSpace": 10, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 57, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 10.078125, + "leftColumn": 41, + "dynamicBindingPathList": [ + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Hello {{appsmith.user.name || appsmith.user.email}}", + "key": "5ejbjgp4n5", + "isDeprecated": false, + "rightColumn": 57, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "3vgn1hs2ig", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "0", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 44, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 41, + "maxDynamicHeight": 9000, + "fontSize": "1rem", + "minDynamicHeight": 4 + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/fixtures/richTextEditorDsl.json b/app/client/cypress/fixtures/richTextEditorDsl.json new file mode 100644 index 0000000000..49fce6e5a8 --- /dev/null +++ b/app/client/cypress/fixtures/richTextEditorDsl.json @@ -0,0 +1,82 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 380, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 27, + "widgetName": "RichTextEditor1", + "displayName": "Rich Text Editor", + "iconSVG": "/static/media/icon.074d534389d0f6262ecfbd8e81539d08.svg", + "labelText": "Label", + "searchTags": [ + "input", + "rte" + ], + "topRow": 7, + "bottomRow": 38, + "parentRowSpace": 10, + "labelWidth": 5, + "type": "RICH_TEXT_EDITOR_WIDGET", + "hideCard": false, + "mobileRightColumn": 44, + "animateLoading": true, + "parentColumnSpace": 10.078125, + "leftColumn": 9, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "labelPosition": "Top", + "inputType": "html", + "isDisabled": false, + "key": "4xb1pqir3y", + "isRequired": false, + "isDeprecated": false, + "rightColumn": 56, + "isDefaultClickDisabled": true, + "dynamicHeight": "FIXED", + "widgetId": "z67478an8a", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "0", + "tags": [ + "Inputs" + ], + "labelAlignment": "left", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 7, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 20, + "maxDynamicHeight": 9000, + "defaultText": "This is the initial content of the editor", + "minDynamicHeight": 4 + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/fixtures/tabsDsl.json b/app/client/cypress/fixtures/tabsDsl.json new file mode 100644 index 0000000000..6a5bdad8bc --- /dev/null +++ b/app/client/cypress/fixtures/tabsDsl.json @@ -0,0 +1,264 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 380, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 86, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 25, + "widgetName": "Tabs1", + "borderColor": "#E0DEDE", + "isCanvas": true, + "displayName": "Tabs", + "iconSVG": "/static/media/icon.9e3d67c0af9c0bd092dc56240314e18a.svg", + "topRow": 10, + "bottomRow": 29, + "parentRowSpace": 10, + "type": "TABS_WIDGET", + "hideCard": false, + "shouldScrollContents": true, + "mobileRightColumn": 45, + "animateLoading": true, + "parentColumnSpace": 5.453125, + "leftColumn": 21, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [ + { + "tabId": "tab1", + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 150, + "widgetName": "Canvas1", + "displayName": "Canvas", + "bottomRow": 150, + "topRow": 0, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 150, + "mobileRightColumn": 130.875, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [], + "isDisabled": false, + "key": "0g64f23mqn", + "isDeprecated": false, + "tabName": "Tab 1", + "rightColumn": 130.875, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "wmb0y3145q", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "bcyu5pg160", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 4, + "flexLayers": [] + }, + { + "tabId": "tab2", + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 150, + "widgetName": "Canvas2", + "displayName": "Canvas", + "bottomRow": 150, + "topRow": 0, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "hideCard": true, + "shouldScrollContents": false, + "minHeight": 150, + "mobileRightColumn": 130.875, + "parentColumnSpace": 1, + "leftColumn": 0, + "dynamicBindingPathList": [ + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + } + ], + "children": [], + "isDisabled": false, + "key": "0g64f23mqn", + "isDeprecated": false, + "tabName": "Tab 2", + "rightColumn": 130.875, + "detachFromLayout": true, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "k2wjfz9vu7", + "minWidth": 450, + "isVisible": true, + "version": 1, + "parentId": "bcyu5pg160", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0, + "maxDynamicHeight": 9000, + "minDynamicHeight": 4, + "flexLayers": [] + } + ], + "borderWidth": 1, + "key": "ptp44kovku", + "backgroundColor": "#FFFFFF", + "isDeprecated": false, + "rightColumn": 45, + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "bcyu5pg160", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "defaultTab": "Tab 1", + "shouldShowTabs": true, + "minWidth": 450, + "tabsObj": { + "tab1": { + "label": "Tab 1", + "id": "tab1", + "widgetId": "wmb0y3145q", + "isVisible": true, + "index": 0, + "positioning": "vertical" + }, + "tab2": { + "label": "Tab 2", + "id": "tab2", + "widgetId": "k2wjfz9vu7", + "isVisible": true, + "index": 1, + "positioning": "vertical" + } + }, + "isVisible": true, + "version": 3, + "parentId": "0", + "tags": [ + "Layout" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 10, + "responsiveBehavior": "fill", + "originalTopRow": 10, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 21, + "maxDynamicHeight": 9000, + "originalBottomRow": 29, + "minDynamicHeight": 15 + }, + { + "mobileBottomRow": 38, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 32, + "bottomRow": 36, + "parentRowSpace": 10, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 40, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 5.453125, + "leftColumn": 25, + "dynamicBindingPathList": [ + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Hello {{appsmith.user.name || appsmith.user.email}}", + "key": "5ejbjgp4n5", + "isDeprecated": false, + "rightColumn": 41, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "wawch01apl", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "0", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 34, + "responsiveBehavior": "fill", + "originalTopRow": 32, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 24, + "maxDynamicHeight": 9000, + "originalBottomRow": 36, + "fontSize": "1rem", + "minDynamicHeight": 4 + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/fixtures/testdata.json b/app/client/cypress/fixtures/testdata.json index bd4348db33..713ae59667 100644 --- a/app/client/cypress/fixtures/testdata.json +++ b/app/client/cypress/fixtures/testdata.json @@ -142,7 +142,7 @@ "v2Key": "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI", "v3Key": "6LcnzQgfAAAAAMwMlQLppqx7STvZ6pZJoDMXti8k", "invalidKey": "abc123", - "errorMsg": "Google Re-Captcha token generation failed! Please check the Re-captcha site key.", + "errorMsg": "Google reCAPTCHA token generation failed! Please check the reCAPTCHA site key.", "treeTextBindingValue": "{{TreeSelect1.selectedOptionValue}}", "multiSelectTextBindingValue": "{{MultiSelect1.selectedOptionValues}}", "tabBindingValue": "{{Tabs1.selectedTab}}", @@ -163,5 +163,8 @@ "fileBindingValue": "{{FilePicker1.isDirty}}", "UPGRADEUSERNAME": "arslan+upgrade160@appsmith.com", "UPGRADEPASSWORD": "Test@123", - "APPURL": "http://localhost:8081/app/app1/page1-63d38854252ca15b7ec9fabb" + "APPURL": "http://localhost:8081/app/app1/page1-63d38854252ca15b7ec9fabb", + "iframeUrl": "https://elfsight.com/social-feed-widget/iframe/", + "iframeUrlSubstring": "https://elfsight.com/", + "iframeRandomUrl": "https://www.google.com" } diff --git a/app/client/cypress/fixtures/videoWidgetApp.json b/app/client/cypress/fixtures/videoWidgetApp.json new file mode 100644 index 0000000000..0fe242d479 --- /dev/null +++ b/app/client/cypress/fixtures/videoWidgetApp.json @@ -0,0 +1,281 @@ +{ + "clientSchemaVersion": 1.0, + "serverSchemaVersion": 6.0, + "exportedApplication": { + "name": "videoWidget", + "isPublic": false, + "pages": [{ "id": "Page1", "isDefault": true }], + "publishedPages": [{ "id": "Page1", "isDefault": true }], + "viewMode": false, + "appIsExample": false, + "unreadCommentThreads": 0.0, + "color": "#D9E7FF", + "icon": "couples", + "slug": "videowidget", + "unpublishedCustomJSLibs": [], + "publishedCustomJSLibs": [], + "evaluationVersion": 2.0, + "applicationVersion": 2.0, + "collapseInvisibleWidgets": true, + "isManualUpdate": false, + "deleted": false + }, + "datasourceList": [], + "customJSLibList": [], + "pageList": [ + { + "unpublishedPage": { + "name": "Page1", + "slug": "page1", + "layouts": [ + { + "viewMode": false, + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896.0, + "snapColumns": 64.0, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0.0, + "bottomRow": 640.0, + "containerStyle": "none", + "snapRows": 124.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 85.0, + "minHeight": 1292.0, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1.0, + "dynamicBindingPathList": [], + "leftColumn": 0.0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 29.0, + "widgetName": "Video1", + "displayName": "Video", + "iconSVG": "/static/media/icon.e3e5dfc92ff10e68a8a2b3c94ab4a4a4.svg", + "searchTags": ["youtube"], + "topRow": 1.0, + "bottomRow": 29.0, + "parentRowSpace": 10.0, + "type": "VIDEO_WIDGET", + "hideCard": false, + "mobileRightColumn": 42.0, + "animateLoading": true, + "parentColumnSpace": 9.859375, + "leftColumn": 3.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "key": "voiurkp8ai", + "backgroundColor": "#000", + "isDeprecated": false, + "rightColumn": 57.0, + "widgetId": "qjfil0t0kv", + "isVisible": true, + "version": 1.0, + "url": "https://assets.appsmith.com/widgets/bird.mp4", + "parentId": "0", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 18.0, + "autoPlay": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 64.0, + "widgetName": "Camera1", + "isCanvas": false, + "displayName": "Camera", + "iconSVG": "/static/media/icon.c18f801ae183dba33c7a61ea80204a5d.svg", + "searchTags": ["photo", "video recorder"], + "topRow": 31.0, + "bottomRow": 64.0, + "parentRowSpace": 10.0, + "type": "CAMERA_WIDGET", + "hideCard": false, + "mode": "VIDEO", + "mobileRightColumn": 35.0, + "parentColumnSpace": 9.859375, + "dynamicTriggerPathList": [], + "leftColumn": 10.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "isDisabled": false, + "key": "suq81f35gl", + "isMirrored": true, + "isDeprecated": false, + "rightColumn": 50.0, + "widgetId": "qlwgd0ivcc", + "isVisible": true, + "version": 1.0, + "parentId": "0", + "tags": ["External"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 31.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 10.0 + } + ] + }, + "layoutOnLoadActions": [], + "layoutOnLoadActionErrors": [], + "validOnPageLoadActions": true, + "id": "Page1", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "userPermissions": [], + "policies": [] + }, + "publishedPage": { + "name": "Page1", + "slug": "page1", + "layouts": [ + { + "viewMode": false, + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896.0, + "snapColumns": 64.0, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0.0, + "bottomRow": 640.0, + "containerStyle": "none", + "snapRows": 124.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 85.0, + "minHeight": 1292.0, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1.0, + "dynamicBindingPathList": [], + "leftColumn": 0.0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "mobileBottomRow": 29.0, + "widgetName": "Video1", + "displayName": "Video", + "iconSVG": "/static/media/icon.e3e5dfc92ff10e68a8a2b3c94ab4a4a4.svg", + "searchTags": ["youtube"], + "topRow": 1.0, + "bottomRow": 29.0, + "parentRowSpace": 10.0, + "type": "VIDEO_WIDGET", + "hideCard": false, + "mobileRightColumn": 42.0, + "animateLoading": true, + "parentColumnSpace": 9.859375, + "leftColumn": 3.0, + "dynamicBindingPathList": [ + { "key": "borderRadius" }, + { "key": "boxShadow" } + ], + "key": "voiurkp8ai", + "backgroundColor": "#000", + "isDeprecated": false, + "rightColumn": 57.0, + "widgetId": "qjfil0t0kv", + "isVisible": true, + "version": 1.0, + "url": "https://assets.appsmith.com/widgets/bird.mp4", + "parentId": "0", + "tags": ["Media"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 1.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 18.0, + "autoPlay": false + }, + { + "boxShadow": "none", + "mobileBottomRow": 64.0, + "widgetName": "Camera1", + "isCanvas": false, + "displayName": "Camera", + "iconSVG": "/static/media/icon.c18f801ae183dba33c7a61ea80204a5d.svg", + "searchTags": ["photo", "video recorder"], + "topRow": 31.0, + "bottomRow": 64.0, + "parentRowSpace": 10.0, + "type": "CAMERA_WIDGET", + "hideCard": false, + "mode": "VIDEO", + "mobileRightColumn": 35.0, + "parentColumnSpace": 9.859375, + "dynamicTriggerPathList": [], + "leftColumn": 10.0, + "dynamicBindingPathList": [{ "key": "borderRadius" }], + "isDisabled": false, + "key": "suq81f35gl", + "isMirrored": true, + "isDeprecated": false, + "rightColumn": 50.0, + "widgetId": "qlwgd0ivcc", + "isVisible": true, + "version": 1.0, + "parentId": "0", + "tags": ["External"], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 31.0, + "responsiveBehavior": "hug", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 10.0 + } + ] + }, + "layoutOnLoadActions": [], + "layoutOnLoadActionErrors": [], + "validOnPageLoadActions": true, + "id": "Page1", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "userPermissions": [], + "policies": [] + }, + "deleted": false, + "gitSyncId": "64e3dc9900e46367acc7bfb3_64e3dc9900e46367acc7bfb5" + } + ], + "actionList": [], + "actionCollectionList": [], + "updatedResources": { + "customJSLibList": [], + "actionList": [], + "pageList": ["Page1"], + "actionCollectionList": [] + }, + "editModeTheme": { + "name": "Default", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false + }, + "publishedTheme": { + "name": "Default", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false + } +} diff --git a/app/client/cypress/fixtures/videoWidgetDsl.json b/app/client/cypress/fixtures/videoWidgetDsl.json deleted file mode 100644 index f9eec36594..0000000000 --- a/app/client/cypress/fixtures/videoWidgetDsl.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "dsl": { - "widgetName": "MainContainer", - "backgroundColor": "none", - "rightColumn": 1224, - "snapColumns": 16, - "detachFromLayout": true, - "widgetId": "0", - "topRow": 0, - "bottomRow": 1280, - "containerStyle": "none", - "snapRows": 33, - "parentRowSpace": 1, - "type": "CANVAS_WIDGET", - "canExtend": true, - "dynamicBindingPathList": [], - "version": 6, - "minHeight": 1292, - "parentColumnSpace": 1, - "leftColumn": 0, - "children": [ - { - "isVisible": true, - "widgetName": "Video1", - "url": "https://assets.appsmith.com/widgets/bird.mp4", - "autoPlay": false, - "type": "VIDEO_WIDGET", - "isLoading": false, - "parentColumnSpace": 74, - "parentRowSpace": 40, - "leftColumn": 1, - "rightColumn": 8, - "topRow": 17, - "bottomRow": 24, - "parentId": "0", - "widgetId": "fvilzim02v" - } - ] - } -} diff --git a/app/client/cypress/fixtures/xmlParser.json b/app/client/cypress/fixtures/xmlParser.json index ed63586a5c..65573652b8 100644 --- a/app/client/cypress/fixtures/xmlParser.json +++ b/app/client/cypress/fixtures/xmlParser.json @@ -1,64 +1,342 @@ { - "dsl": { - "widgetName": "MainContainer", - "backgroundColor": "none", - "rightColumn": 1224, - "snapColumns": 16, - "detachFromLayout": true, - "widgetId": "0", - "topRow": 0, - "bottomRow": 1280, - "containerStyle": "none", - "snapRows": 33, - "parentRowSpace": 1, - "type": "CANVAS_WIDGET", - "canExtend": true, - "version": 7, - "minHeight": 1292, - "parentColumnSpace": 1, - "leftColumn": 0, - "dynamicBindingPathList": [], - "children": [ + "clientSchemaVersion": 1.0, + "serverSchemaVersion": 6.0, + "exportedApplication": { + "name": "xml_paser_test", + "isPublic": false, + "pages": [ { - "isVisible": true, - "text": "{{xmlParser.parse(Input1.text) }}", - "textStyle": "LABEL", - "textAlign": "LEFT", - "widgetName": "Text1", - "type": "TEXT_WIDGET", - "isLoading": false, - "parentColumnSpace": 74, - "parentRowSpace": 40, - "leftColumn": 3, - "rightColumn": 8, - "topRow": 3, - "bottomRow": 10, - "parentId": "0", - "widgetId": "axlcnmjk4t", - "dynamicBindingPathList": [ - { - "key": "text" - } - ] - }, - { - "isVisible": true, - "inputType": "TEXT", - "label": "", - "widgetName": "Input1", - "type": "INPUT_WIDGET_V2", - "isLoading": false, - "parentColumnSpace": 74, - "parentRowSpace": 40, - "leftColumn": 3, - "rightColumn": 8, - "topRow": 2, - "bottomRow": 3, - "parentId": "0", - "widgetId": "8n5urob9mz", - "dynamicBindingPathList": [], - "defaultText": " Tove Jani Reminder Don't forget me this weekend! " + "id": "Page1", + "isDefault": true } - ] + ], + "publishedPages": [ + { + "id": "Page1", + "isDefault": true + } + ], + "viewMode": false, + "appIsExample": false, + "unreadCommentThreads": 0.0, + "color": "#EAEDFB", + "icon": "yen", + "slug": "xml-paser-test", + "unpublishedCustomJSLibs": [], + "publishedCustomJSLibs": [], + "evaluationVersion": 2.0, + "applicationVersion": 2.0, + "collapseInvisibleWidgets": true, + "isManualUpdate": false, + "deleted": false + }, + "datasourceList": [], + "customJSLibList": [], + "pageList": [ + { + "unpublishedPage": { + "name": "Page1", + "slug": "page1", + "layouts": [ + { + "viewMode": false, + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896.0, + "snapColumns": 64.0, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0.0, + "bottomRow": 380.0, + "containerStyle": "none", + "snapRows": 124.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 87.0, + "minHeight": 1292.0, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1.0, + "dynamicBindingPathList": [], + "leftColumn": 0.0, + "children": [ + { + "mobileBottomRow": 14.0, + "widgetName": "Text1", + "displayName": "Text", + "iconSVG": "https://release-appcdn.appsmith.com/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 0.0, + "bottomRow": 16.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 23.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 14.953125, + "dynamicTriggerPathList": [], + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{xmlParser.parse(Input1.text)}}", + "key": "bdg0tfrf6x", + "isDeprecated": false, + "rightColumn": 13.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "b8blvt9b2z", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "0", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 10.0, + "responsiveBehavior": "fill", + "originalTopRow": 0.0, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 7.0, + "maxDynamicHeight": 9000.0, + "originalBottomRow": 4.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + }, + { + "boxShadow": "none", + "iconSVG": "https://release-appcdn.appsmith.com/static/media/icon.f2c34197dbcf03595098986de898928f.svg", + "topRow": 17.0, + "labelWidth": 5.0, + "type": "INPUT_WIDGET_V2", + "animateLoading": true, + "resetOnSubmit": true, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + } + ], + "labelStyle": "", + "inputType": "TEXT", + "isDisabled": false, + "isRequired": false, + "dynamicHeight": "FIXED", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "showStepArrows": false, + "isVisible": true, + "version": 2.0, + "tags": [ + "Suggested", + "Inputs" + ], + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "originalBottomRow": 21.0, + "mobileBottomRow": 21.0, + "widgetName": "Input1", + "displayName": "Input", + "searchTags": [ + "form", + "text input", + "number", + "textarea" + ], + "bottomRow": 24.0, + "parentRowSpace": 10.0, + "autoFocus": false, + "hideCard": false, + "mobileRightColumn": 19.0, + "parentColumnSpace": 14.34375, + "dynamicTriggerPathList": [], + "labelPosition": "Top", + "key": "mx0emg6xlv", + "labelTextSize": "0.875rem", + "isDeprecated": false, + "rightColumn": 19.0, + "widgetId": "ni16fc0xys", + "minWidth": 450.0, + "label": "Label", + "parentId": "0", + "labelAlignment": "left", + "renderMode": "CANVAS", + "mobileTopRow": 14.0, + "responsiveBehavior": "fill", + "originalTopRow": 14.0, + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "iconAlign": "left", + "defaultText": " Tove Jani Reminder Don't forget me this weekend! ", + "minDynamicHeight": 4.0 + }, + { + "mobileBottomRow": 35.0, + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "https://release-appcdn.appsmith.com/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg", + "searchTags": [ + "typography", + "paragraph", + "label" + ], + "topRow": 31.0, + "bottomRow": 35.0, + "parentRowSpace": 10.0, + "type": "TEXT_WIDGET", + "hideCard": false, + "mobileRightColumn": 16.0, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 14.34375, + "leftColumn": 0.0, + "dynamicBindingPathList": [ + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "Hello {{appsmith.user.name || appsmith.user.email}}", + "key": "bdg0tfrf6x", + "isDeprecated": false, + "rightColumn": 20.0, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "3m7c3st35v", + "minWidth": 450.0, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1.0, + "parentId": "0", + "tags": [ + "Suggested", + "Content" + ], + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 31.0, + "responsiveBehavior": "fill", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 0.0, + "maxDynamicHeight": 9000.0, + "fontSize": "1rem", + "minDynamicHeight": 4.0 + } + ] + }, + "layoutOnLoadActions": [], + "layoutOnLoadActionErrors": [], + "validOnPageLoadActions": true, + "id": "Page1", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "userPermissions": [], + "policies": [] + }, + "publishedPage": { + "name": "Page1", + "slug": "page1", + "layouts": [ + { + "viewMode": false, + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 1224.0, + "snapColumns": 16.0, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0.0, + "bottomRow": 1250.0, + "containerStyle": "none", + "snapRows": 33.0, + "parentRowSpace": 1.0, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 4.0, + "minHeight": 1292.0, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1.0, + "dynamicBindingPathList": [], + "leftColumn": 0.0, + "children": [] + }, + "validOnPageLoadActions": true, + "id": "Page1", + "deleted": false, + "policies": [], + "userPermissions": [] + } + ], + "userPermissions": [], + "policies": [] + }, + "deleted": false, + "gitSyncId": "6529174c97a7581320fb6a4f_6529174c97a7581320fb6a51" + } + ], + "actionList": [], + "actionCollectionList": [], + "updatedResources": { + "customJSLibList": [], + "actionList": [], + "pageList": [ + "Page1" + ], + "actionCollectionList": [] + }, + "editModeTheme": { + "name": "Default-New", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false + }, + "publishedTheme": { + "name": "Default-New", + "displayName": "Modern", + "isSystemTheme": true, + "deleted": false } -} +} \ No newline at end of file diff --git a/app/client/cypress/locators/AdminsSettings.js b/app/client/cypress/locators/AdminsSettings.js index 6ccffb48cf..ba9e74523b 100644 --- a/app/client/cypress/locators/AdminsSettings.js +++ b/app/client/cypress/locators/AdminsSettings.js @@ -4,7 +4,7 @@ export default { advancedTab: ".t--settings-category-advanced", authenticationTab: ".t--settings-category-authentication", emailTab: ".t--settings-category-email", - googleMapsTab: ".t--settings-category-google-maps", + developerSettingsTab: ".t--settings-category-developer-settings", googleButton: ".t--settings-sub-category-google-auth", githubButton: ".t--settings-sub-category-github-auth", formloginButton: ".t--settings-sub-category-form-login", @@ -18,6 +18,7 @@ export default { adminEmails: ".t--admin-settings-APPSMITH_ADMIN_EMAILS input", fromAddress: ".t--admin-settings-APPSMITH_MAIL_FROM input", restartNotice: ".t--admin-settings-restart-notice", + appsmithStarting: "p:contains('Appsmith is starting')", appsmithLogo: ".t--appsmith-logo", appsmithHeader: "[data-testid='t--appsmith-page-header']", loginWithGoogle: "[data-testid='login-with-Google']", @@ -34,4 +35,6 @@ export default { brandingSubmitButton: ".t--settings-branding-submit-button", businessTag: "[data-testid='t--business-tag']", enterpriseTag: "[data-testid='t--enterprise-tag']", + enableEmailVerificationInput: "[data-testid='emailVerificationEnabled']", + adminSettingsCallout: "[data-testid='admin-settings-group-link']", }; diff --git a/app/client/cypress/locators/Applications.json b/app/client/cypress/locators/Applications.json index 0f22c1f76e..e79a30d28b 100644 --- a/app/client/cypress/locators/Applications.json +++ b/app/client/cypress/locators/Applications.json @@ -1,6 +1,7 @@ { "copyUrl": ".t--copy-url", "forkButton": ".t--fork-app", + "forkModal": ".fork-modal", "shareButton": "button:contains('Share')", "placeholderTxt": "//input[@placeholder='Enter email address(es)']", "placeholderTxtEE": "//input[@placeholder='Enter email address(es) or group(s)']", diff --git a/app/client/cypress/locators/OneClickBindingLocator.ts b/app/client/cypress/locators/OneClickBindingLocator.ts index 781a8e4bb9..1d291b4e04 100644 --- a/app/client/cypress/locators/OneClickBindingLocator.ts +++ b/app/client/cypress/locators/OneClickBindingLocator.ts @@ -27,9 +27,7 @@ export default { tableOrSpreadsheetDropdown: '[data-testid="t--one-click-binding-table-selector"] .rc-select-selector', tableOrSpreadsheetDropdownOption: (table?: string) => - `[data-testId='t--one-click-binding-table-selector--table']${ - table ? `:contains(${table})` : "" - }`, + `//div[@data-testId='t--one-click-binding-table-selector--table']//div[text()='${table}']`, tableOrSpreadsheetSelectedOption: (table?: string) => `[data-testid="t--one-click-binding-table-selector"] .rc-select-selection-item${ table ? `:contains(${table})` : "" @@ -44,6 +42,9 @@ export default { datasourceSearch: `[data-testId="t--one-click-binding-datasource--search"]`, searchableColumn: '[data-testId="t--one-click-binding-column-searchableColumn"]', + formType: '[data-testId="t--one-click-binding-column-formType"]', + defaultValues: '[data-testId="t--one-click-binding-column-defaultValues"]', + dataIdentifier: '[data-testId="t--one-click-binding-column-dataIdentifier"]', label: '[data-testId="t--one-click-binding-column-label"]', value: '[data-testId="t--one-click-binding-column-value"]', columnDropdownOption: (column: string, value?: string) => @@ -54,4 +55,11 @@ export default { `[data-testId="t--one-click-binding-column-${column}"] .rc-select-selection-item${ value ? `:contains(${value})` : "" }`, + columnSelectorModalTrigger: '[data-testid="t--edit-fields-button"]', + columnSelectorModal: '[data-testid="t--column-selector-modal"]', + columnselectorModalSaveBtn: '[data-testid="t--edit-fields-save-btn"]', + columnselectorModalCancelBtn: '[data-testid="t--edit-fields-cancel-btn"]', + columnSelectorField: (columnName: string) => + `[data-column-id="t--edit-field-${columnName}"]`, + checkBox: ".ads-v2-checkbox", }; diff --git a/app/client/cypress/locators/SignupPage.json b/app/client/cypress/locators/SignupPage.json index dbf3abf882..b0e403c07b 100644 --- a/app/client/cypress/locators/SignupPage.json +++ b/app/client/cypress/locators/SignupPage.json @@ -3,7 +3,9 @@ "password": "input[name='password']", "submitBtn": "button[type='submit']", "roleDropdown": ".setup-dropdown:first", + "proficiencyGroupButton": "[data-testid='t--user-proficiency'] button", + "useCaseGroupButton": "[data-testid='t--user-use-case'] button", "useCaseDropdown": ".setup-dropdown:last", "dropdownOption": ".rc-select-item-option:first", - "roleUsecaseSubmit": ".t--get-started-button" -} + "getStartedSubmit": ".t--get-started-button" +} \ No newline at end of file diff --git a/app/client/cypress/locators/TemplatesLocators.json b/app/client/cypress/locators/TemplatesLocators.json index c9790dc18c..4ff4ded720 100644 --- a/app/client/cypress/locators/TemplatesLocators.json +++ b/app/client/cypress/locators/TemplatesLocators.json @@ -8,5 +8,6 @@ "templateDialogBox": "[data-testid=t--templates-dialog-component]", "selectCheckbox": ".ads-v2-checkbox", "closeButton": "//button[@aria-label='Close']//span", - "marketingDashboard": "//h1[text()='Marketing Dashboard']" + "marketingDashboard": "//h1[text()='Marketing Dashboard']", + "vehicleMaintenenceApp": "//h1[text()='Vehicle Maintenance App']" } diff --git a/app/client/cypress/locators/WidgetLocators.ts b/app/client/cypress/locators/WidgetLocators.ts index ed911766a4..c02bb0f7ea 100644 --- a/app/client/cypress/locators/WidgetLocators.ts +++ b/app/client/cypress/locators/WidgetLocators.ts @@ -44,6 +44,9 @@ export const WIDGET = { STATBOX: "statboxwidget", JSONFORM: "jsonformwidget", MENUBUTTON: "menubuttonwidget", + DATEPICKER: "datepickerwidget2", + MAP: "mapwidget", + MAPCHART: "mapchartwidget", } as const; // property pane element selector are maintained here @@ -65,6 +68,47 @@ export const WIDGETSKIT = { recorderStart: "//button[@status='DEFAULT']", recorderComplete: "//button[@status='COMPLETE']", recorderStop: ".bp3-minimal", + video: "video", + iFrame: "iframe", + videoWidgetYoutubeMuteBtn: ".ytp-mute-button", + videoWidgetYoutubeLargePlayBtn: ".ytp-large-play-button", + videoWidgetYoutubePlayBtn: ".ytp-play-button", + videoWidgetYoutubeVolumeBtn: ".ytp-volume-panel", + image: "div[data-testid=styledImage]", + imageDownloadBtn: "//a[@data-testid='t--image-download']", + imageRotateAntiClockwiseBtn: + "//div[contains(@class, 't--widget-imagewidget')]//a[1]", + imageRotateClockwiseBtn: + "//div[contains(@class, 't--widget-imagewidget')]//a[2]", + styleResetBtn: ".reset-button", + styleOrangeIcon: ".rounded-full", + dividerVertical: "[data-testid=dividerVertical]", + dividerHorizontal: "[data-testid=dividerHorizontal]", + selectWidgetBtn: ".select-button", + selectWidgetLabel: '//label[contains(@class,"select-label")]', + selectWidgetLabelContainer: + '//label[contains(@class,"select-label")]//parent::span/parent::span/parent::div', + widgetNameTag: "span.t--widget-name", + selectWidgetFilter: ".select-popover-wrapper .bp3-input-group input", + selectWidgetClear: "[data-testid='selectbutton.btn.cancel']", + selectWidgetWidthPlusBtn: ".ads-v2-input__input-section-icon-end", + selectWidgetPlaceholder: (value: string) => + `//span[contains(@title,'${value}')]`, + textWidgetLink: (link: string) => `//a[@href='${link}']`, + textWidgetContainer: ".t--text-widget-container", + inputWidgetLabel: ".t--input-widget-label", + inputWidgetUnMaskPassword: '[name="eye-on"]', + inputWidgetMaskPassword: '[name="eye-off"]', + inputWidgetWrapper: ".text-input-wrapper", + inputWidgetStepUp: + "//*[contains(@class, 'bp3-icon-chevron-up')]//parent::button", + inputWidgetStepDown: + "//*[contains(@class, 'bp3-icon-chevron-down')]//parent::button", + radioWidgetContainer: "[data-testid='radiogroup-container']", + radioBtn: ".bp3-radio", + radioWidgetLabel: ".radiogroup-label", + radioWidgetLabelContainer: + "[data-testid='radiogroup-container'] .label-container", }; type ValueOf = T[keyof T]; @@ -92,7 +136,42 @@ export const switchlocators = { }; export const checkboxlocators = { - // read Blue here checkBoxLabel: (value: string) => `//*[contains(@class,'t--checkbox-widget-label') and text()='${value}']`, }; + +export const datePickerlocators = { + options: `//*[contains(@id,'rc_select_') and @role='option']`, + input: `//*[@class='bp3-input-group']//input`, + dayPick: `//*[contains(@class,'DayPicker-Day')]`, + selectYear: `//*[contains(@class,'bp3-datepicker-year-select')]//select//option`, + selectMonth: `//*[contains(@class,'bp3-datepicker-month-select')]//select//option`, + yearCaret: `//*[contains(@class,'bp3-datepicker-year-select')]//*[contains(@class,'bp3-icon-double-caret-vertical')]`, + monthCaret: `//*[contains(@class,'bp3-datepicker-month-select')]//*[contains(@class,'bp3-icon-double-caret-vertical')]`, + yearInDropdown: (year: string) => + datePickerlocators.selectYear + `[@value='${year}']`, + monthInDropdown: (month: string) => + datePickerlocators.selectMonth + `[@label='${month}']`, + inputHour: `.bp3-timepicker-hour`, + inputMinute: `.bp3-timepicker-minute`, + inputSecond: `.bp3-timepicker-second`, + weekDay: `//*[@class='DayPicker-Weekday']//*[@title]`, + calendarHeader: `//*[contains(@class,'datepicker__calender-header')]//*[@type='button']`, + year: (yearToSelect: string) => `//*[@data-value='${yearToSelect}']`, + date: (dateToSelect: string) => + `//*[contains(@class,'datepicker__day--${dateToSelect}')]`, +}; + +export const buttongroupwidgetlocators = { + buttongroup: ".t--buttongroup-widget", + buttonSettingInPropPane: ".t--property-control-buttons .t--edit-column-btn", + menuSettingInPropPane: ".t--edit-column-btn", + newButton: "//*[text()='Add new button']", + groupButtonValue: "//input[contains(@value,'Group Button')]", + buttonText: (value: string) => + `//*[@class="bp3-button-text" and text()='${value}']`, + menu: "[data-value='MENU']", + buttonMenuOptions: (text: string) => + `//*[contains(@class,'bp3-menu-item')]//*[text()='${text}']`, + button: "//*[contains(@class,'t--widget-buttongroupwidget')]//button", +}; diff --git a/app/client/cypress/locators/gitSyncLocators.js b/app/client/cypress/locators/gitSyncLocators.js index 848dea7eff..efd96e0431 100644 --- a/app/client/cypress/locators/gitSyncLocators.js +++ b/app/client/cypress/locators/gitSyncLocators.js @@ -30,7 +30,7 @@ export default { disabledConnectGitBottomBar: ".t--disabled-connect-git-bottom-bar", syncBranches: ".t--sync-branches", closeBranchList: ".t--close-branch-list", - learnMoreDeployKey: "//span[text()='Learn More']", + learnMoreDeployKey: "//span[text()='Learn more']", learnMoreSshUrl: ".t--learn-more-ssh-url", readDocument: ".t--read-document", gitConnectErrorLearnMore: diff --git a/app/client/cypress/locators/welcomePage.json b/app/client/cypress/locators/welcomePage.json index be3b0b57d4..4a8e79cc3f 100644 --- a/app/client/cypress/locators/welcomePage.json +++ b/app/client/cypress/locators/welcomePage.json @@ -1,9 +1,10 @@ { - "firstName":".t--welcome-form-first-name input", - "lastName":".t--welcome-form-last-name input", - "email":".t--welcome-form-email input", - "password":".t--welcome-form-password input", - "verifyPassword":".t--welcome-form-verify-password input", + "firstName": ".t--welcome-form-first-name input", + "lastName": ".t--welcome-form-last-name input", + "email": ".t--welcome-form-email input", + "password": ".t--welcome-form-password input", + "verifyPassword": ".t--welcome-form-verify-password input", + "proficiencyGroupButton": ".radio_group__button_container button", "roleDropdown": ".t--welcome-form-role-dropdown .setup-dropdown", "roleDropdownOption": ".rc-select-item-option", "roleInput": ".t--welcome-form-role-input input", diff --git a/app/client/cypress/package.json b/app/client/cypress/package.json deleted file mode 100644 index 5cf8bbf2a4..0000000000 --- a/app/client/cypress/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "appsmith-ci-test", - "version": "0.1.0", - "private": true, - "engines": { - "node": "^18.17.1", - "yarn": "^3.5.1" - }, - "scripts": { - "install": "node apply-patches.js" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ], - "devDependencies": { - "@blueprintjs/core": "^3.36.0", - "@blueprintjs/datetime": "^3.23.6", - "@blueprintjs/icons": "^3.10.0", - "@blueprintjs/popover2": "^0.5.0", - "@blueprintjs/select": "^3.10.0", - "@faker-js/faker": "^7.4.0", - "@typescript-eslint/eslint-plugin": "^5.25.0", - "@typescript-eslint/parser": "^5.25.0", - "chalk": "^4.1.1", - "cy-verify-downloads": "^0.0.5", - "cypress": "^12.17.4", - "cypress-file-upload": "^4.1.1", - "cypress-image-snapshot": "^4.0.1", - "cypress-log-to-output": "^1.1.2", - "cypress-multi-reporters": "^1.2.4", - "cypress-plugin-tab": "^1.0.5", - "cypress-real-events": "^1.8.1", - "cypress-tags": "^1.1.2", - "cypress-wait-until": "^1.7.2", - "cypress-xpath": "^1.4.0", - "diff": "^5.0.0", - "dotenv": "^8.1.0", - "eslint-plugin-cypress": "^2.11.2", - "tinycolor2": "^1.4.2", - "typescript": "4.9.5" - } -} diff --git a/app/client/cypress/plugins/index.js b/app/client/cypress/plugins/index.js index d594688142..3ec32eaa60 100644 --- a/app/client/cypress/plugins/index.js +++ b/app/client/cypress/plugins/index.js @@ -3,14 +3,14 @@ const fs = require("fs"); const path = require("path"); const dotenv = require("dotenv"); const chalk = require("chalk"); -// const _ = require("lodash"); -// const del = require("del"); const cypressLogToOutput = require("cypress-log-to-output"); -//const { isFileExist } = require("cy-verify-downloads"); +const installLogsPrinter = require("cypress-terminal-report/src/installLogsPrinter"); const { addMatchImageSnapshotPlugin, } = require("cypress-image-snapshot/plugin"); const { tagify } = require("cypress-tags"); +const { cypressHooks } = require("../scripts/cypress-hooks"); +const { cypressSplit } = require("../scripts/cypress-split"); // *********************************************************** // This example plugins/index.js can be used to load plugins // @@ -28,7 +28,7 @@ const { tagify } = require("cypress-tags"); * @type {Cypress.PluginConfig} */ -module.exports = (on, config) => { +module.exports = async (on, config) => { // on("task", { // isFileExist, // }); @@ -42,6 +42,16 @@ module.exports = (on, config) => { return false; }); + const logsPrinterOptions = { + outputRoot: config.projectRoot + "/cypress/", + outputTarget: { + "cypress-logs|json": "json", + }, + specRoot: "cypress/e2e", + printLogsToFile: "onFail", + }; + installLogsPrinter(on, logsPrinterOptions); + on("file:preprocessor", tagify(config)); addMatchImageSnapshotPlugin(on, config); @@ -74,9 +84,9 @@ module.exports = (on, config) => { // && browser.isHeadless) { launchOptions.preferences.fullscreen = true; launchOptions.preferences.darkTheme = true; - launchOptions["width"] = 1400; - launchOptions["height"] = 1100; - launchOptions["resizable"] = false; + launchOptions.preferences.width = 1400; + launchOptions.preferences.height = 1100; + launchOptions.preferences.resizable = false; return launchOptions; } }); @@ -213,5 +223,10 @@ module.exports = (on, config) => { }, }); + if (process.env["RUNID"]) { + config = await new cypressSplit().splitSpecs(on, config); + cypressHooks(on, config); + } + return config; }; diff --git a/app/client/cypress/scripts/cypress-hooks.ts b/app/client/cypress/scripts/cypress-hooks.ts new file mode 100644 index 0000000000..50a1dbc189 --- /dev/null +++ b/app/client/cypress/scripts/cypress-hooks.ts @@ -0,0 +1,147 @@ +import os from "os"; +import util from "./util"; + +export async function cypressHooks( + on: Cypress.PluginEvents, + config: Cypress.PluginConfigOptions, +) { + const _ = new util(); + const s3 = _.configureS3(); + const dbClient = _.configureDbClient(); + const runData: any = { + workflowId: _.getVars().runId, + attempt: _.getVars().attempt_number, + os: os.type(), + }; + const matrix: any = { + matrixId: _.getVars().thisRunner, + matrixStatus: "started", + }; + const specData: any = {}; + + on("before:run", async (runDetails: Cypress.BeforeRunDetails) => { + runData.browser = runDetails.browser?.name; + const client = await dbClient.connect(); + try { + const attemptRes = await client.query( + `UPDATE public."attempt" SET "browser" = $1, "os" = $2 WHERE "workflowId" = $3 AND attempt = $4 RETURNING id`, + [runData.browser, runData.os, runData.workflowId, runData.attempt], + ); + runData.attemptId = attemptRes.rows[0].id; + const matrixRes = await client.query( + `SELECT id FROM public."matrix" WHERE "attemptId" = $1 AND "matrixId" = $2`, + [runData.attemptId, matrix.matrixId], + ); + matrix.id = matrixRes.rowCount > 0 ? matrixRes.rows[0].id : ""; + } catch (err) { + console.log(err); + } finally { + client.release(); + } + }); + + on("before:spec", async (spec: Cypress.Spec) => { + specData.name = spec.relative; + specData.matrixId = matrix.id; + const client = await dbClient.connect(); + try { + if (!specData.name.includes("no_spec.ts")) { + const specResponse = await client.query( + `UPDATE public."specs" SET "status" = $1 WHERE "name" = $2 AND "matrixId" = $3 RETURNING id`, + ["in-progress", specData.name, matrix.id], + ); + specData.specId = specResponse.rows[0].id; + } + } catch (err) { + console.log(err); + } finally { + client.release(); + } + }); + + on( + "after:spec", + async (spec: Cypress.Spec, results: CypressCommandLine.RunResult) => { + const client = await dbClient.connect(); + try { + if (!specData.name.includes("no_spec.ts")) { + await client.query( + 'UPDATE public.specs SET "testCount" = $1, "passes" = $2, "failed" = $3, "skipped" = $4, "pending" = $5, "status" = $6, "duration" = $7 WHERE id = $8', + [ + results.stats.tests, + results.stats.passes, + results.stats.failures, + results.stats.skipped, + results.stats.pending, + results.stats.failures > 0 ? "fail" : "pass", + results.stats.duration, + specData.specId, + ], + ); + for (const test of results.tests) { + const testResponse = await client.query( + `INSERT INTO public.tests ("name", "specId", "status", "retries", "retryData") VALUES ($1, $2, $3, $4, $5) RETURNING id`, + [ + test.title[1], + specData.specId, + test.state, + test.attempts.length, + test.displayError, + ], + ); + if ( + test.attempts.some((attempt) => attempt.state === "failed") && + results.screenshots.length > 0 + ) { + const out = results.screenshots.filter((scr) => + scr.path.includes(test.title[1]), + ); + console.log("Uploading screenshots..."); + for (const scr of out) { + const attempt = scr.path.includes("attempt 2") ? 2 : 1; + const key = `${testResponse.rows[0].id}_${specData.specId}_${attempt}`; + await _.uploadToS3(s3, scr.path, key); + } + } + } + + if ( + results.tests.some((test) => + test.attempts.some((attempt) => attempt.state === "failed"), + ) && + results.video + ) { + console.log("Uploading video..."); + const key = `${specData.specId}`; + await _.uploadToS3(s3, results.video, key); + } + } + } catch (err) { + console.log(err); + } finally { + client.release(); + } + }, + ); + + on("after:run", async (runDetails) => { + const client = await dbClient.connect(); + try { + if (!specData.name.includes("no_spec.ts")) { + await client.query( + `UPDATE public.matrix SET "status" = $1 WHERE id = $2`, + ["done", matrix.id], + ); + await client.query( + `UPDATE public.attempt SET "endTime" = $1 WHERE "id" = $2`, + [new Date(), runData.attemptId], + ); + } + } catch (err) { + console.log(err); + } finally { + client.release(); + await dbClient.end(); + } + }); +} diff --git a/app/client/cypress/scripts/cypress-split.ts b/app/client/cypress/scripts/cypress-split.ts new file mode 100644 index 0000000000..3bfc47e606 --- /dev/null +++ b/app/client/cypress/scripts/cypress-split.ts @@ -0,0 +1,328 @@ +/* eslint-disable no-console */ +import util from "./util"; +import globby from "globby"; +import minimatch from "minimatch"; + +export class cypressSplit { + util = new util(); + dbClient = this.util.configureDbClient(); + + // This function will get all the spec paths using the pattern + private async getSpecFilePaths( + specPattern: any, + ignoreTestFiles: any, + ): Promise { + const files = globby.sync(specPattern, { + ignore: ignoreTestFiles, + }); + + // ignore the files that doesn't match + const ignorePatterns = [...(ignoreTestFiles || [])]; + + // a function which returns true if the file does NOT match + const doesNotMatchAllIgnoredPatterns = (file: string) => { + // using {dot: true} here so that folders with a '.' in them are matched + const MINIMATCH_OPTIONS = { dot: true, matchBase: true }; + return ignorePatterns.every((pattern) => { + return !minimatch(file, pattern, MINIMATCH_OPTIONS); + }); + }; + const filtered = files.filter(doesNotMatchAllIgnoredPatterns); + return filtered; + } + + private async getSpecsWithTime(specs: string[], attemptId: number) { + const client = await this.dbClient.connect(); + const defaultDuration = 180000; + const specsMap = new Map(); + try { + const queryRes = await client.query( + 'SELECT * FROM public."spec_avg_duration" ORDER BY duration DESC', + ); + + queryRes.rows.forEach((obj) => { + specsMap.set(obj.name, obj); + }); + + const allSpecsWithDuration = specs.map((spec) => { + const match = specsMap.get(spec); + return match ? match : { name: spec, duration: defaultDuration }; + }); + const activeRunners = await this.util.getActiveRunners(); + const activeRunnersFromDb = await this.getActiveRunnersFromDb(attemptId); + return await this.util.divideSpecsIntoBalancedGroups( + allSpecsWithDuration, + Number(activeRunners) - Number(activeRunnersFromDb), + ); + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + // This function will finally get the specs as a comma separated string to pass the specs to the command + private async getSpecsToRun( + specPattern: string | string[] = "cypress/e2e/**/**/*.{js,ts}", + ignorePattern: string | string[], + attemptId: number, + ): Promise { + try { + const specFilePaths = await this.getSpecFilePaths( + specPattern, + ignorePattern, + ); + + const specsToRun = await this.getSpecsWithTime(specFilePaths, attemptId); + console.log("SPECS TO RUN ----------> :", specsToRun); + return specsToRun === undefined || specsToRun.length === 0 + ? [] + : specsToRun[0].map((spec) => spec.name); + } catch (err) { + console.error(err); + process.exit(1); + } + } + + private async getActiveRunnersFromDb(attemptId: number) { + const client = await this.dbClient.connect(); + try { + const matrixRes = await client.query( + `SELECT * FROM public."matrix" WHERE "attemptId" = $1`, + [attemptId], + ); + return matrixRes.rowCount; + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async getAlreadyRunningSpecs() { + const client = await this.dbClient.connect(); + try { + const dbRes = await client.query( + `SELECT name FROM public."specs" + WHERE "matrixId" IN + (SELECT id FROM public."matrix" + WHERE "attemptId" = ( + SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2 + ) + )`, + [this.util.getVars().runId, this.util.getVars().attempt_number], + ); + const specs: string[] = + dbRes.rows.length > 0 ? dbRes.rows.map((row) => row.name) : []; + return specs; + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async createAttempt() { + const client = await this.dbClient.connect(); + try { + const runResponse = await client.query( + `INSERT INTO public."attempt" ("workflowId", "attempt", "repo", "committer", "type", "commitMsg", "branch") + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT ("workflowId", attempt) DO NOTHING + RETURNING id;`, + [ + this.util.getVars().runId, + this.util.getVars().attempt_number, + this.util.getVars().repository, + this.util.getVars().committer, + this.util.getVars().tag, + this.util.getVars().commitMsg, + this.util.getVars().branch, + ], + ); + + if (runResponse.rows.length > 0) { + return runResponse.rows[0].id; + } else { + const res = await client.query( + `SELECT id FROM public."attempt" WHERE "workflowId" = $1 AND attempt = $2`, + [this.util.getVars().runId, this.util.getVars().attempt_number], + ); + return res.rows[0].id; + } + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async createMatrix(attemptId: number) { + const client = await this.dbClient.connect(); + try { + const matrixResponse = await client.query( + `INSERT INTO public."matrix" ("workflowId", "matrixId", "status", "attemptId") + VALUES ($1, $2, $3, $4) + ON CONFLICT ("matrixId", "attemptId") DO NOTHING + RETURNING id;`, + [ + this.util.getVars().runId, + this.util.getVars().thisRunner, + "started", + attemptId, + ], + ); + return matrixResponse.rows[0].id; + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async getFailedSpecsFromPreviousRun( + workflowId = Number(this.util.getVars().runId), + attempt_number = Number(this.util.getVars().attempt_number) - 1, + ) { + const client = await this.dbClient.connect(); + try { + const dbRes = await client.query( + `SELECT name FROM public."specs" + WHERE "matrixId" IN + (SELECT id FROM public."matrix" + WHERE "attemptId" = ( + SELECT id FROM public."attempt" WHERE "workflowId" = $1 and "attempt" = $2 + ) + ) AND status IN ('fail', 'queued', 'in-progress')`, + [workflowId, attempt_number], + ); + const specs: string[] = + dbRes.rows.length > 0 ? dbRes.rows.map((row) => row.name) : []; + return specs; + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async addSpecsToMatrix(matrixId: number, specs: string[]) { + const client = await this.dbClient.connect(); + try { + for (const spec of specs) { + const res = await client.query( + `INSERT INTO public."specs" ("name", "matrixId", "status") VALUES ($1, $2, $3) RETURNING id`, + [spec, matrixId, "queued"], + ); + } + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async addLockGetTheSpecs( + attemptId: number, + specPattern: string | string[], + ignorePattern: string | string[], + ) { + const client = await this.dbClient.connect(); + let specs: string[] = []; + let locked = false; + let counter = 1; + try { + while (counter <= 120 && !locked) { + const result = await client.query( + `UPDATE public."attempt" SET is_locked = true WHERE id = $1 AND is_locked = false RETURNING id`, + [attemptId], + ); + if (result.rows.length === 1) { + locked = true; + let runningSpecs: string[] = + (await this.getAlreadyRunningSpecs()) ?? []; + if (typeof ignorePattern === "string") { + runningSpecs.push(ignorePattern); + ignorePattern = runningSpecs; + } else { + ignorePattern = runningSpecs.concat(ignorePattern); + } + specs = await this.getSpecsToRun( + specPattern, + ignorePattern, + attemptId, + ); + return specs; + } else { + await this.sleep(5000); + counter++; + } + } + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async updateTheSpecsAndReleaseLock( + attemptId: number, + specs: string[], + ) { + const client = await this.dbClient.connect(); + try { + if (specs.length > 0) { + const matrixRes = await this.createMatrix(attemptId); + await this.addSpecsToMatrix(matrixRes, specs); + } + await client.query( + `UPDATE public."attempt" SET is_locked = false WHERE id = $1 AND is_locked = true RETURNING id`, + [attemptId], + ); + } catch (err) { + console.log(err); + } finally { + client.release(); + } + } + + private async sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + public async splitSpecs( + on: Cypress.PluginEvents, + config: Cypress.PluginConfigOptions, + ) { + try { + let specPattern = config.specPattern; + let ignorePattern: string | string[] = config.excludeSpecPattern; + const cypressSpecs = this.util.getVars().cypressSpecs; + const defaultSpec = "cypress/scripts/no_spec.ts"; + + if (cypressSpecs != "") + specPattern = cypressSpecs?.split(",").filter((val) => val !== ""); + if (this.util.getVars().cypressRerun === "true") { + specPattern = + (await this.getFailedSpecsFromPreviousRun()) ?? defaultSpec; + } + + const attempt = await this.createAttempt(); + const specs = + (await this.addLockGetTheSpecs(attempt, specPattern, ignorePattern)) ?? + []; + if (specs.length > 0 && !specs.includes(defaultSpec)) { + config.specPattern = specs.length == 1 ? specs[0] : specs; + } else { + config.specPattern = defaultSpec; + } + await this.updateTheSpecsAndReleaseLock(attempt, specs); + + return config; + } catch (err) { + console.log(err); + } finally { + this.dbClient.end(); + } + } +} diff --git a/app/client/cypress/scripts/no_spec.ts b/app/client/cypress/scripts/no_spec.ts new file mode 100644 index 0000000000..98f3e69d0a --- /dev/null +++ b/app/client/cypress/scripts/no_spec.ts @@ -0,0 +1 @@ +// This file is to run when no cypress specs found. diff --git a/app/client/cypress/scripts/util.ts b/app/client/cypress/scripts/util.ts new file mode 100644 index 0000000000..858e09c01b --- /dev/null +++ b/app/client/cypress/scripts/util.ts @@ -0,0 +1,149 @@ +import { Pool } from "pg"; +import AWS from "aws-sdk"; +import fs from "fs"; +import { Octokit } from "@octokit/rest"; +import fetch from "node-fetch"; + +export interface DataItem { + name: string; + duration: string; +} +export default class util { + public getVars() { + return { + runId: this.getEnvValue("RUNID", { required: true }), + attempt_number: this.getEnvValue("ATTEMPT_NUMBER", { required: true }), + repository: this.getEnvValue("REPOSITORY", { required: true }), + committer: this.getEnvValue("COMMITTER", { required: true }), + tag: this.getEnvValue("TAG", { required: true }), + branch: this.getEnvValue("BRANCH", { required: true }), + cypressDbUser: this.getEnvValue("CYPRESS_DB_USER", { required: true }), + cypressDbHost: this.getEnvValue("CYPRESS_DB_HOST", { required: true }), + cypressDbName: this.getEnvValue("CYPRESS_DB_NAME", { required: true }), + cypressDbPwd: this.getEnvValue("CYPRESS_DB_PWD", { required: true }), + cypressS3Access: this.getEnvValue("CYPRESS_S3_ACCESS", { + required: true, + }), + cypressS3Secret: this.getEnvValue("CYPRESS_S3_SECRET", { + required: true, + }), + githubToken: process.env["GITHUB_TOKEN"], + commitMsg: this.getEnvValue("COMMIT_INFO_MESSAGE", { required: false }), + totalRunners: this.getEnvValue("TOTAL_RUNNERS", { required: false }), + thisRunner: this.getEnvValue("THIS_RUNNER", { required: true }), + cypressSpecs: this.getEnvValue("CYPRESS_SPECS", { required: false }), + cypressRerun: this.getEnvValue("CYPRESS_RERUN", { required: false }), + }; + } + + public async divideSpecsIntoBalancedGroups( + data: DataItem[], + numberOfGroups: number, + ): Promise { + const groups: DataItem[][] = Array.from( + { length: numberOfGroups }, + () => [], + ); + data.forEach((item) => { + // Find the group with the shortest total duration and add the item to it + const shortestGroupIndex = groups.reduce( + (minIndex, group, currentIndex) => { + const totalDuration = groups[minIndex].reduce( + (acc, item) => acc + Number(item.duration), + 0, + ); + const totalDurationCurrent = group.reduce( + (acc, item) => acc + Number(item.duration), + 0, + ); + return totalDurationCurrent < totalDuration ? currentIndex : minIndex; + }, + 0, + ); + groups[shortestGroupIndex].push(item); + }); + return groups; + } + + public getEnvValue(varName: string, { required = true }): string { + if (required && process.env[varName] === undefined) { + throw Error( + `${varName} is not defined. + Please check all the following environment variables are defined properly + [ RUNID, ATTEMPT_NUMBER, REPOSITORY, COMMITTER, TAG, BRANCH, THIS_RUNNER, CYPRESS_DB_USER, CYPRESS_DB_HOST, CYPRESS_DB_NAME, CYPRESS_DB_PWD, CYPRESS_S3_ACCESS, CYPRESS_S3_SECRET ].`, + ); + } + return process.env[varName] ?? ""; + } + + //This is to setup the db client + public configureDbClient() { + const dbConfig = { + user: this.getVars().cypressDbUser, + host: this.getVars().cypressDbHost, + database: this.getVars().cypressDbName, + password: this.getVars().cypressDbPwd, + port: 5432, + connectionTimeoutMillis: 60000, + ssl: true, + keepalives: 30, + }; + const dbClient = new Pool(dbConfig); + return dbClient; + } + + // This is to setup the AWS client + public configureS3() { + AWS.config.update({ region: "ap-south-1" }); + const s3client = new AWS.S3({ + credentials: { + accessKeyId: this.getVars().cypressS3Access, + secretAccessKey: this.getVars().cypressS3Secret, + }, + }); + return s3client; + } + + // This is to upload files to s3 when required + public async uploadToS3(s3Client: AWS.S3, filePath: string, key: string) { + const fileContent = fs.readFileSync(filePath); + const params = { + Bucket: "appsmith-internal-cy-db", + Key: key, + Body: fileContent, + }; + return await s3Client.upload(params).promise(); + } + + public async getActiveRunners() { + const octokit = new Octokit({ + auth: this.getVars().githubToken, + request: { + fetch: fetch, + }, + }); + try { + const repo: string[] = this.getVars().repository.split("/"); + const response = await octokit.request( + "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs", + { + owner: repo[0], + repo: repo[1], + run_id: Number(this.getVars().runId), + per_page: 100, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }, + ); + const active_runners = response.data.jobs.filter( + (job) => + (job.status === "in_progress" || job.status === "queued") && + job.run_attempt === Number(this.getVars().attempt_number), + ); + return active_runners.length; + } catch (error) { + console.error("Error:", error); + } + } +} diff --git a/app/client/cypress/snapshots/3DCustomECharts.snap.png b/app/client/cypress/snapshots/3DCustomECharts.snap.png new file mode 100644 index 0000000000..4e66133b5b Binary files /dev/null and b/app/client/cypress/snapshots/3DCustomECharts.snap.png differ diff --git a/app/client/cypress/snapshots/Expired Token.snap.png b/app/client/cypress/snapshots/Expired Token.snap.png new file mode 100644 index 0000000000..41ad5e09ea Binary files /dev/null and b/app/client/cypress/snapshots/Expired Token.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithBorderRadius.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithBorderRadius.snap.png new file mode 100644 index 0000000000..8a69529aff Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithBorderRadius.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithBoxShadow.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithBoxShadow.snap.png new file mode 100644 index 0000000000..331e5b13b6 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithBoxShadow.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithColorRange.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithColorRange.snap.png new file mode 100644 index 0000000000..174cb9b0f2 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapChartWithColorRange.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapchartsimple.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapchartsimple.snap.png new file mode 100644 index 0000000000..8c2f89fd4e Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapchartsimple.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithafrica.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithafrica.snap.png new file mode 100644 index 0000000000..0ae073e47c Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithafrica.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithantarctica.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithantarctica.snap.png new file mode 100644 index 0000000000..9bfd9b8400 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithantarctica.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithasia.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithasia.snap.png new file mode 100644 index 0000000000..377f29bb32 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithasia.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithcustomdata.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithcustomdata.snap.png new file mode 100644 index 0000000000..51f4fd6073 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithcustomdata.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithcustomtitle.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithcustomtitle.snap.png new file mode 100644 index 0000000000..324e7ee9e9 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithcustomtitle.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwitheurope.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwitheurope.snap.png new file mode 100644 index 0000000000..add3836286 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwitheurope.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithnorthamerica.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithnorthamerica.snap.png new file mode 100644 index 0000000000..caa38c331a Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithnorthamerica.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithoceania.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithoceania.snap.png new file mode 100644 index 0000000000..bdb2c33820 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithoceania.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithshowlabelsoff.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithshowlabelsoff.snap.png new file mode 100644 index 0000000000..b09f3de3a8 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithshowlabelsoff.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithshowlableson.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithshowlableson.snap.png new file mode 100644 index 0000000000..324e7ee9e9 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithshowlableson.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithsouthamerica.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithsouthamerica.snap.png new file mode 100644 index 0000000000..235f11b233 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithsouthamerica.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithusa.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithusa.snap.png new file mode 100644 index 0000000000..86c2ea5a43 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithusa.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithvisibilityoff.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithvisibilityoff.snap.png new file mode 100644 index 0000000000..2a8d68fa82 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithvisibilityoff.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithvisibilityon.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithvisibilityon.snap.png new file mode 100644 index 0000000000..324e7ee9e9 Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithvisibilityon.snap.png differ diff --git a/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithworld.snap.png b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithworld.snap.png new file mode 100644 index 0000000000..8c2f89fd4e Binary files /dev/null and b/app/client/cypress/snapshots/MapChart_Spec.ts/mapwithworld.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithBorderRadius.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithBorderRadius.snap.png new file mode 100644 index 0000000000..073ed59d28 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithBorderRadius.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithBoxShadow.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithBoxShadow.snap.png new file mode 100644 index 0000000000..9d02413822 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithBoxShadow.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultMarker1.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultMarker1.snap.png new file mode 100644 index 0000000000..79b48d2857 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultMarker1.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultMarker2.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultMarker2.snap.png new file mode 100644 index 0000000000..a27c00a799 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultMarker2.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultZoomIn.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultZoomIn.snap.png new file mode 100644 index 0000000000..af196e948d Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultZoomIn.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultZoomOut.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultZoomOut.snap.png new file mode 100644 index 0000000000..c30e60de62 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithDefaultZoomOut.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnableSearchLocationOff.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnableSearchLocationOff.snap.png new file mode 100644 index 0000000000..912836e846 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnableSearchLocationOff.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnablingClusteringON.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnablingClusteringON.snap.png new file mode 100644 index 0000000000..df9aa88996 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnablingClusteringON.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnablingClusteringOff.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnablingClusteringOff.snap.png new file mode 100644 index 0000000000..a61315a9e0 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithEnablingClusteringOff.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithInitalLocation.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithInitalLocation.snap.png new file mode 100644 index 0000000000..9734ba0ba3 Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithInitalLocation.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithMapNMarkerCenteringOff.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithMapNMarkerCenteringOff.snap.png new file mode 100644 index 0000000000..7efb7e7d5c Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithMapNMarkerCenteringOff.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithPickLocationOff.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithPickLocationOff.snap.png new file mode 100644 index 0000000000..7efb7e7d5c Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithPickLocationOff.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithVisibilityOff.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithVisibilityOff.snap.png new file mode 100644 index 0000000000..3c8da7146c Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithVisibilityOff.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithVisibilityOnWithJS.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithVisibilityOnWithJS.snap.png new file mode 100644 index 0000000000..af196e948d Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithVisibilityOnWithJS.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithinItalLocationAsJS.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithinItalLocationAsJS.snap.png new file mode 100644 index 0000000000..f84ce5da5d Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapWithinItalLocationAsJS.snap.png differ diff --git a/app/client/cypress/snapshots/MapWidget_Spec.ts/mapsimple.snap.png b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapsimple.snap.png new file mode 100644 index 0000000000..7e1c9ff5cb Binary files /dev/null and b/app/client/cypress/snapshots/MapWidget_Spec.ts/mapsimple.snap.png differ diff --git a/app/client/cypress/snapshots/Unknown error.snap.png b/app/client/cypress/snapshots/Unknown error.snap.png new file mode 100644 index 0000000000..d697a8dc8b Binary files /dev/null and b/app/client/cypress/snapshots/Unknown error.snap.png differ diff --git a/app/client/cypress/snapshots/VerificationPendingScreen.snap.png b/app/client/cypress/snapshots/VerificationPendingScreen.snap.png new file mode 100644 index 0000000000..ca51475765 Binary files /dev/null and b/app/client/cypress/snapshots/VerificationPendingScreen.snap.png differ diff --git a/app/client/cypress/snapshots/Verified Token.snap.png b/app/client/cypress/snapshots/Verified Token.snap.png new file mode 100644 index 0000000000..62763e0df3 Binary files /dev/null and b/app/client/cypress/snapshots/Verified Token.snap.png differ diff --git a/app/client/cypress/snapshots/WrongToken.snap.png b/app/client/cypress/snapshots/WrongToken.snap.png new file mode 100644 index 0000000000..2410734218 Binary files /dev/null and b/app/client/cypress/snapshots/WrongToken.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/areachartsnapshot.snap.png b/app/client/cypress/snapshots/chartwidget/areachartsnapshot.snap.png new file mode 100644 index 0000000000..19f12d0e4e Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/areachartsnapshot.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/areachartsnapshotwithlabels.snap.png b/app/client/cypress/snapshots/chartwidget/areachartsnapshotwithlabels.snap.png new file mode 100644 index 0000000000..d7168ce308 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/areachartsnapshotwithlabels.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/columnchartsnapshot.snap.png b/app/client/cypress/snapshots/chartwidget/columnchartsnapshot.snap.png new file mode 100644 index 0000000000..ed10abc967 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/columnchartsnapshot.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithadaptiveaxis.snap.png b/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithadaptiveaxis.snap.png new file mode 100644 index 0000000000..d67bf8abb7 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithadaptiveaxis.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithlabels.snap.png b/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithlabels.snap.png new file mode 100644 index 0000000000..85ea6e2917 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithlabels.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithoutadaptiveaxis.snap.png b/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithoutadaptiveaxis.snap.png new file mode 100644 index 0000000000..c184abd328 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/columnchartsnapshotwithoutadaptiveaxis.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/linechartWithAutoXAxisLabelOrientation.snap.png b/app/client/cypress/snapshots/chartwidget/linechartWithAutoXAxisLabelOrientation.snap.png new file mode 100644 index 0000000000..983bd2fac3 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/linechartWithAutoXAxisLabelOrientation.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/linechartWithRotateXAxisLabelOrientation.snap.png b/app/client/cypress/snapshots/chartwidget/linechartWithRotateXAxisLabelOrientation.snap.png new file mode 100644 index 0000000000..e0a524f6e2 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/linechartWithRotateXAxisLabelOrientation.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/linechartWithSlantXAxisLabelOrientation.snap.png b/app/client/cypress/snapshots/chartwidget/linechartWithSlantXAxisLabelOrientation.snap.png new file mode 100644 index 0000000000..99f54011aa Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/linechartWithSlantXAxisLabelOrientation.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/linechartsnapshot.snap.png b/app/client/cypress/snapshots/chartwidget/linechartsnapshot.snap.png new file mode 100644 index 0000000000..4ce11795c6 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/linechartsnapshot.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/linechartsnapshotwithlabels.snap.png b/app/client/cypress/snapshots/chartwidget/linechartsnapshotwithlabels.snap.png new file mode 100644 index 0000000000..c07975dbfc Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/linechartsnapshotwithlabels.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/piechartsnapshot.snap.png b/app/client/cypress/snapshots/chartwidget/piechartsnapshot.snap.png new file mode 100644 index 0000000000..6461580181 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/piechartsnapshot.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/piechartsnapshotwithlabels.snap.png b/app/client/cypress/snapshots/chartwidget/piechartsnapshotwithlabels.snap.png new file mode 100644 index 0000000000..d84973a5e4 Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/piechartsnapshotwithlabels.snap.png differ diff --git a/app/client/cypress/snapshots/chartwidget/piechartsnapshotwithtitle.snap.png b/app/client/cypress/snapshots/chartwidget/piechartsnapshotwithtitle.snap.png new file mode 100644 index 0000000000..05acfe7fbe Binary files /dev/null and b/app/client/cypress/snapshots/chartwidget/piechartsnapshotwithtitle.snap.png differ diff --git a/app/client/cypress/support/AdminSettingsCommands.js b/app/client/cypress/support/AdminSettingsCommands.js index 605286753b..78553b9848 100644 --- a/app/client/cypress/support/AdminSettingsCommands.js +++ b/app/client/cypress/support/AdminSettingsCommands.js @@ -78,7 +78,11 @@ Cypress.Commands.add("waitForServerRestart", () => { // cy.waitUntil(() => !Cypress.$(adminSettings.restartNotice).length, { // timeout: 180000, // }); - cy.get(adminSettings.restartNotice, { timeout: 210000 }).should("not.exist"); + cy.get(adminSettings.restartNotice, { timeout: 300000 }).should("not.exist"); + cy.get(adminSettings.appsmithStarting, { timeout: 300000 }).should( + "not.exist", + ); + cy.window().then((win) => { win.location.reload(); }); diff --git a/app/client/cypress/support/ApiCommands.js b/app/client/cypress/support/ApiCommands.js index 0682ac045d..f6b640caab 100644 --- a/app/client/cypress/support/ApiCommands.js +++ b/app/client/cypress/support/ApiCommands.js @@ -110,18 +110,7 @@ Cypress.Commands.add( (apiName, baseurl, path, verb, error = false) => { cy.get(".ads-v2-tabs__list").contains("Logs").click(); cy.get("[data-testid=t--debugger-search]").clear().type(apiName); - agHelper.PressEnter(); - agHelper.Sleep(); - - cy.get("body").then(($ele) => { - if ($ele.find(ApiEditor.apiResponseObject).length <= 0) { - agHelper - .GetElement(ApiEditor.apiDebuggerLink) - .last() - .contains(apiName) - .click(); - } - }); + agHelper.PressEnter(2000); if (!error) { cy.get(ApiEditor.apiResponseObject).last().contains("request").click(); } diff --git a/app/client/cypress/support/Constants.js b/app/client/cypress/support/Constants.js index e7c68bda97..dceddedd16 100644 --- a/app/client/cypress/support/Constants.js +++ b/app/client/cypress/support/Constants.js @@ -93,3 +93,31 @@ export const TABLE_DATA = `{{[ "orderAmount": 7.99 } ]}}`; + +export const TABLE_DATA_STATIC = ` +[ + { + "id": "#1", + "task": "Drop a table", + "status": "✅", + "action": "" + }, + { + "id": "#2", + "task": "Create a query fetch_users with the Mock DB", + "status": "--", + "action": "" + }, + { + "id": "#3", + "task": "Bind the query using => fetch_users.data", + "status": "--", + "action": "" + } +] +`; + +export const WALKTHROUGH_TEST_PAGE = "WALKTHROUGH_TEST_PAGE"; +export const DEFAULT_COLUMN_NAME = "Table Column"; +export const FEATURE_WALKTHROUGH_INDEX_KEY = "FEATURE_WALKTHROUGH"; +export const USER_SIGN_UP_INDEX_KEY = "USER_SIGN_UP"; diff --git a/app/client/cypress/support/Objects/CommonLocators.ts b/app/client/cypress/support/Objects/CommonLocators.ts index b839f954b5..0c63f41001 100644 --- a/app/client/cypress/support/Objects/CommonLocators.ts +++ b/app/client/cypress/support/Objects/CommonLocators.ts @@ -81,7 +81,8 @@ export class CommonLocators { item + "']/ancestor::div[@role='menuitem']"; _visibleTextDiv = (divText: string) => "//div[text()='" + divText + "']"; - _visibleTextSpan = (spanText: string) => `//span[text()="` + spanText + `"]`; + _visibleTextSpan = (spanText: string, isCss = false) => + isCss ? `span:contains("${spanText}")` : `//span[text()="${spanText}"]`; _openWidget = ".widgets .t--entity-add-btn"; _dropHere = ".t--drop-target"; _editPage = "[data-testid=onboarding-tasks-datasource-text], .t--drop-target"; @@ -245,17 +246,16 @@ export class CommonLocators { `//button[contains(@class, 't--open-dropdown-${value}')]`; _fixedLayout = "#t--layout-conversion-cta:contains('fixed')"; _forkAppToWorkspaceBtn = ".t--fork-app-to-workspace-button"; - _popoverToolTip = ".bp3-popover-content"; + _popoverToolTip = ".bp3-popover-content, .bp3-popover2-content"; _selectedWidget = "div[data-testid='t--selected']"; _appsmithWidget = (widgetId: string) => `.appsmith_widget_${widgetId}`; _selectionCanvas = (canvasId: string) => `#div-selection-${canvasId}`; _sqlKeyword = ".cm-m-sql.cm-keyword"; _appLeveltooltip = (toolTip: string) => `span:contains('${toolTip}')`; - _appEditMenu = "[data-testid='t--application-edit-menu']"; - _appEditMenuBtn = "[data-testid='t--application-edit-menu-cta']"; - _appEditMenuSettings = "[data-testid='t--application-edit-menu-settings']"; - _appEditExportSettings = - "[data-testid='t--application-edit-menu-export-application']"; + _appEditMenu = "[data-testid='t--editor-menu']"; + _appEditMenuBtn = "[data-testid='t--editor-menu-cta']"; + _appEditMenuSettings = "[data-testid='t--editor-menu-settings']"; + _appEditExportSettings = "[data-testid='t--editor-menu-export-application']"; _appThemeSettings = "#t--theme-settings-header"; _appChangeThemeBtn = ".t--change-theme-btn"; _appThemeCard = ".t--theme-card"; @@ -273,10 +273,57 @@ export class CommonLocators { _svg = "svg"; _imgWidgetInsideList = `//div[@data-testid='styledImage']//img`; _containerWidget = "[type='CONTAINER_WIDGET']"; + _statboxWidget = "[type='STATBOX_WIDGET']"; _evaluatedValue = ".t-property-evaluated-value"; public ds_editor_env_filter = (envName: string) => `[data-testid="t--ds-data-filter-${envName}"]`; _textWidgetContaioner = ".t--text-widget-container span"; + _label = ".bp3-label"; + _input = ".bp3-input"; + _tooltipIcon = ".bp3-popover-target svg"; + _checkboxHelpIcon = ".bp3-popover-target svg"; + _checkboxWidgetLabel = ".t--checkbox-widget-label"; _buttonWidgetInForm = "//*[contains(@class,'t--widget-buttonwidget')]//button[contains(@class,'bp3-button')]"; + _walkthrough_overlay = `.t--walkthrough-overlay`; + _autoHeightHandles = "[data-testid='t-auto-height-overlay-handles']"; + _autoHeightMin = "[data-testid='t--auto-height-overlay-handles-min']"; + _autoHeightMax = "[data-testid='t--auto-height-overlay-handles-max']"; + _position = (value: string) => `//*[@data-value='${value}']`; + _alignment = (value: string) => `//*[@data-value='${value}']`; + _borderRadius = (value: string) => `//*[@data-value='${value}']`; + _textInside = ".bp3-ui-text span"; + _listActivePage = ".t--widget-listwidgetv2 .rc-pagination-item-active"; + _hintsList = "ul.CodeMirror-hints"; + _buttonInDeployedMode = ".bp3-button"; + _treeSelectPlaceholder = ".rc-tree-select-selection-placeholder"; + _treeSelectTitle = ".rc-tree-select-tree-title"; + _newDataSourceBtn = ".datasources .t--entity-add-btn"; + _callbackAddBtn = ".action-callback-add .ads-v2-button"; + _checkboxInDeployedMode = "//label[contains(@class, 'bp3-checkbox')]//input"; + _listText = "//span[text()='Blue']/../.."; + _jsonFormSubmitBtn = ".t--jsonform-submit-btn"; + _jsonFormResetBtn = ".t--jsonform-reset-btn"; + _draggableFieldConfig = (fieldName: string) => + `[data-rbd-draggable-id=${fieldName}]`; + _fileUploadDashboardClose = ".uppy-Dashboard-close"; + _fileUploadErrorContains = (msg: string) => + `.uppy-Informer p:contains('${msg}')`; + _fileUploadAddMore = ".uppy-DashboardContent-addMore"; + _buttonText = ".bp3-button-text"; + _richText_TitleBlock = "[title='Blocks']"; + _richText_Heading = "[title='Heading 1']"; + _richText_Label_Text = ".tox-tbtn__select-label"; + _richText_Text_Color = '[title="Text color"] .tox-split-button__chevron'; + _richText_color = (value: string) => `[title='${value}']`; + _richText_line = "#tinymce p span"; + _treeSelectedContent = ".rc-tree-select-selection-item-content"; + _switcherIcon = ".switcher-icon"; + _root = "#root"; + _pageHeaderToggle = ".mobile-ui-page-header-toggle-icon"; + _pageHeaderMenuList = ".mobile-ui-page-header-menu-list"; + _enterFullScreen = ".application-demo-new-dashboard-control-enter-fullscreen"; + _dashboardContainer = ".application-demo-new-dashboard-container"; + _exitFullScreen = ".application-demo-new-dashboard-control-exit-fullscreen"; + _menuItem = ".bp3-menu-item"; } diff --git a/app/client/cypress/support/Objects/DataManager.ts b/app/client/cypress/support/Objects/DataManager.ts index d6b1ec35a1..26d921e5c6 100644 --- a/app/client/cypress/support/Objects/DataManager.ts +++ b/app/client/cypress/support/Objects/DataManager.ts @@ -10,7 +10,7 @@ export class DataManager { mongo_authenticationAuthtype: "SCRAM-SHA-1", mongo_host: "host.docker.internal", mongo_port: 28017, - mongo_databaseName: "mongo_samples", + mongo_databaseName: "mongo_prod", postgres_host: "host.docker.internal", postgres_port: 5432, @@ -52,11 +52,11 @@ export class DataManager { smtp_username: "root", smtp_password: "root", - oracle_host: "random-data", - oracle_port: 40, - oracle_name: "random-name", - oracle_username: "random-username", - oracle_password: "random-password", + oracle_host: Cypress.env("ORACLE_HOST"), + oracle_port: 1521, + oracle_service: Cypress.env("ORACLE_SERVICE"), + oracle_username: Cypress.env("ORACLE_USERNAME"), + oracle_password: Cypress.env("ORACLE_PASSWORD"), redis_host: "host.docker.internal", redis_port: "6379", @@ -83,6 +83,7 @@ export class DataManager { firestore_database_url: "https://appsmith-22e8b.firebaseio.com", firestore_projectID: "appsmith-22e8b", + firestore_serviceaccountkey: Cypress.env("FIRESTORE_PRIVATE_KEY"), restapi_url: "https://my-json-server.typicode.com/typicode/demo/posts", connection_type: "Replica set", @@ -95,19 +96,22 @@ export class DataManager { authenticatedApiUrl: "https://fakeapi.com", GraphqlApiUrl_TED: "http://host.docker.internal:5000/graphql", + + twilio_username: "random-username", + twilio_password: "random-password", }, Staging: { mongo_authenticationAuthtype: "SCRAM-SHA-1", mongo_host: "host.docker.internal", mongo_port: 28017, - mongo_databaseName: "mongo_samples2", + mongo_databaseName: "mongo_staging", postgres_host: "host.docker.internal", postgres_port: 5432, - postgres_databaseName: "fakeapitest", - postgres_username: "docker", - postgres_password: "docker", + postgres_databaseName: "stagingdb", + postgres_username: "dockerstaging", + postgres_password: "dockerstaging", mysql_host: "host.docker.internal", mysql_port: 3306, @@ -145,7 +149,7 @@ export class DataManager { oracle_host: "random-data", oracle_port: 40, - oracle_name: "random-name", + oracle_service: "random-name", oracle_username: "random-username", oracle_password: "random-password", @@ -170,8 +174,9 @@ export class DataManager { AirtableTableForME: "tblsFCQSskVFf7xNd", ApiUrlME: "http://host.docker.internal:5001/v1/staging", - firestore_database_url: "https://appsmith-22e8b.firebaseio.com", - firestore_projectID: "appsmith-22e8b", + firestore_database_url: "https://staging-sample.firebaseio.com", + firestore_projectID: "appsmith-dummy", + firestore_serviceaccountkey: "dummy_service_creds_key", restapi_url: "https://my-json-server.typicode.com/typicode/demo/posts", connection_type: "Replica set", @@ -184,6 +189,9 @@ export class DataManager { authenticatedApiUrl: "https://fakeapi.com", GraphqlApiUrl_TED: "http://host.docker.internal:5000/graphql", + + twilio_username: "random-username", + twilio_password: "random-password", }, }; diff --git a/app/client/cypress/support/Objects/FeatureFlags.ts b/app/client/cypress/support/Objects/FeatureFlags.ts index 788bde5643..c002462a06 100644 --- a/app/client/cypress/support/Objects/FeatureFlags.ts +++ b/app/client/cypress/support/Objects/FeatureFlags.ts @@ -13,5 +13,6 @@ export const featureFlagIntercept = ( cy.intercept("GET", "/api/v1/users/features", response); if (reload) { cy.reload(); + cy.wait(2000); //for the page to re-load finish for CI runs } }; diff --git a/app/client/cypress/support/Objects/ObjectsCore.ts b/app/client/cypress/support/Objects/ObjectsCore.ts index 6e2d7a717b..8b3337cb1b 100644 --- a/app/client/cypress/support/Objects/ObjectsCore.ts +++ b/app/client/cypress/support/Objects/ObjectsCore.ts @@ -34,3 +34,4 @@ export const entityItems = EntityItems; export const tabs = ObjectsRegistry.Tabs; export const gsheetHelper = ObjectsRegistry.GSheetHelper; export const widgetLocators = WIDGETSKIT; +export const communityTemplates = ObjectsRegistry.CommunityTemplates; diff --git a/app/client/cypress/support/Objects/Registry.ts b/app/client/cypress/support/Objects/Registry.ts index 7a9eafc7ac..27a7258572 100644 --- a/app/client/cypress/support/Objects/Registry.ts +++ b/app/client/cypress/support/Objects/Registry.ts @@ -28,6 +28,7 @@ import { AssertHelper } from "../Pages/AssertHelper"; import { ReusableHelper } from "./ReusableHelper"; import { Tabs } from "../Pages/Tabs"; import { GsheetHelper } from "../Pages/GSheetHelper"; +import { CommunityTemplates } from "../Pages/CommunityTemplates"; export class ObjectsRegistry { private static aggregateHelper__: AggregateHelper; @@ -269,6 +270,14 @@ export class ObjectsRegistry { } return ObjectsRegistry.gsheetHelper__; } + + private static communityTemplates__: CommunityTemplates; + static get CommunityTemplates(): CommunityTemplates { + if (ObjectsRegistry.communityTemplates__ === undefined) { + ObjectsRegistry.communityTemplates__ = new CommunityTemplates(); + } + return ObjectsRegistry.communityTemplates__; + } } export const initLocalstorageRegistry = () => { diff --git a/app/client/cypress/support/Pages/AdminSettings.ts b/app/client/cypress/support/Pages/AdminSettings.ts index 47f34be115..c4506bb040 100644 --- a/app/client/cypress/support/Pages/AdminSettings.ts +++ b/app/client/cypress/support/Pages/AdminSettings.ts @@ -4,6 +4,7 @@ export class AdminSettings { public agHelper = ObjectsRegistry.AggregateHelper; public locator = ObjectsRegistry.CommonLocators; public homePage = ObjectsRegistry.HomePage; + public assertHelper = ObjectsRegistry.AssertHelper; public _adminSettingsBtn = '[data-testid="t--admin-settings-menu-option"]'; private _settingsList = ".t--settings-category-list"; @@ -11,13 +12,13 @@ export class AdminSettings { public _roles = (user: string) => "//span[contains(text(), '" + user + - "')]/parent::div/parent::a/parent::td/following-sibling::td[1]"; - public _instanceName = - "//label[text()='Instance name']/following-sibling::div//input"; + "')]/parent::div/parent::span/parent::a/parent::td/following-sibling::td[1]"; + public _instanceName = '[name="instanceName"]'; public NavigateToAdminSettings() { this.homePage.NavigateToHome(); this.agHelper.GetNClick(this._adminSettingsBtn); + this.assertHelper.AssertNetworkStatus("getEnvVariables"); this.agHelper.AssertElementVisibility(this._settingsList); } } diff --git a/app/client/cypress/support/Pages/AggregateHelper.ts b/app/client/cypress/support/Pages/AggregateHelper.ts index df8658c7fb..c3f34c9006 100644 --- a/app/client/cypress/support/Pages/AggregateHelper.ts +++ b/app/client/cypress/support/Pages/AggregateHelper.ts @@ -37,18 +37,26 @@ const DEFAULT_ENTERVALUE_OPTIONS = { export class AggregateHelper extends ReusableHelper { private locator = ObjectsRegistry.CommonLocators; - public _modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; private assertHelper = ObjectsRegistry.AssertHelper; - public isMac = Cypress.platform === "darwin"; + public get isMac() { + return Cypress.platform === "darwin"; + } private selectLine = `${ this.isMac ? "{cmd}{shift}{leftArrow}" : "{shift}{home}" }`; - private removeLine = "{backspace}"; + public get removeLine() { + return "{backspace}"; + } + public _modifierKey = `${this.isMac ? "meta" : "ctrl"}`; private selectAll = `${this.isMac ? "{cmd}{a}" : "{ctrl}{a}"}`; private lazyCodeEditorFallback = ".t--lazyCodeEditor-fallback"; private lazyCodeEditorRendered = ".t--lazyCodeEditor-editor"; private toolTipSpan = ".rc-tooltip-inner span"; + _walkthroughOverlay = ".t--walkthrough-overlay"; + _walkthroughOverlayClose = ".t--walkthrough-overlay .t--walkthrough-close"; + _walkthroughOverlayTitle = (title: string) => + `//div[contains(@class, 't--walkthrough-overlay')]//p[text()='${title}']`; private selectChars = (noOfChars: number) => `${"{leftArrow}".repeat(noOfChars) + "{shift}{cmd}{leftArrow}{backspace}"}`; @@ -92,6 +100,28 @@ export class AggregateHelper extends ReusableHelper { }); } + public SimulateCopyPaste(action: "copy" | "paste" | "cut") { + const actionToKey = { + copy: "c", + paste: "v", + cut: "x", + }; + const keyToSimulate = actionToKey[action]; + + // Simulate Ctrl keypress (Ctrl down) + this.GetElement(this.locator._body).type(`{${this._modifierKey}}`, { + release: false, + }); + + // Simulate 'C' keypress while Ctrl is held (Ctrl + C) + this.GetElement(this.locator._body).type(keyToSimulate, { release: false }); + + // Release the Ctrl key + this.GetElement(this.locator._body).type(`{${this._modifierKey}}`, { + release: true, + }); + } + public AddDsl( dslFile: string, elementToCheckPresenceaftDslLoad: string | "" = "", // reloadWithoutCache = true, @@ -125,11 +155,12 @@ export class AggregateHelper extends ReusableHelper { }).then((dslDumpResp) => { //cy.log("Pages resposne is : " + dslDumpResp.body); expect(dslDumpResp.status).equal(200); - this.Sleep(3000); //for dsl to settle in layouts api & then refresh + //this.Sleep(3000); //for dsl to settle in layouts api & then refresh this.RefreshPage(); if (elementToCheckPresenceaftDslLoad) this.WaitUntilEleAppear(elementToCheckPresenceaftDslLoad); - this.Sleep(2000); //settling time for dsl + //this.Sleep(2000); //settling time for dsl + this.assertHelper.AssertNetworkResponseData("@getPluginForm"); this.AssertElementAbsence(this.locator._loading); //Checks the spinner is gone & dsl loaded! this.AssertElementAbsence(this.locator._animationSpnner, 20000); //Checks page is loaded with dsl! }); @@ -176,9 +207,8 @@ export class AggregateHelper extends ReusableHelper { .type(renameVal, { force: true, delay: 0 }) .should("have.value", renameVal) .blur(); - this.PressEnter(); + this.PressEnter(); //allow lil more time for new name to settle this.AssertElementVisibility(this.locator._editIcon); - this.Sleep(300); //allow lil more time for new name to settle } public CheckForPageSaveError() { @@ -297,30 +327,57 @@ export class AggregateHelper extends ReusableHelper { } else this.GetNAssertContains(this.locator._toastMsg, text); } - public RemoveTooltip(toolTip: string) { - cy.get("body").then(($body) => { - if ($body.find(this.locator._appLeveltooltip(toolTip)).length > 0) { - this.GetElement(this.locator._appLeveltooltip(toolTip)) - .parents("div.rc-tooltip") - .then(($tooltipElement) => { - $tooltipElement.remove(); - cy.log(toolTip + " tooltip removed"); - }); - } - }); - } - public AssertTooltip(toolTipText: string) { this.GetNAssertContains(this.toolTipSpan, toolTipText); } - public RemoveEvaluatedPopUp() { + public RemoveUIElement( + elementToRemove: "EvaluatedPopUp" | "Tooltip" | "Toast", + toolTipOrToasttext = "", + ) { cy.get("body").then(($body) => { - if ($body.find(this.locator._evalPopup).length > 0) { - this.GetElement(this.locator._evalPopup).then(($evalPopUp) => { - $evalPopUp.remove(); - cy.log("Eval pop up removed"); - }); + switch (elementToRemove) { + case "EvaluatedPopUp": + if ($body.find(this.locator._evalPopup).length > 0) { + this.GetElement(this.locator._evalPopup).then(($evalPopUp) => { + $evalPopUp.remove(); + cy.log("Eval pop up removed"); + }); + } + break; + case "Tooltip": + if ( + $body.find(this.locator._appLeveltooltip(toolTipOrToasttext)) + .length > 0 + ) { + this.GetElement(this.locator._appLeveltooltip(toolTipOrToasttext)) + .parents("div.rc-tooltip") + .then(($tooltipElement) => { + $tooltipElement.remove(); + cy.log(toolTipOrToasttext + " tooltip removed"); + }); + } + break; + case "Toast": + if ( + $body.find( + this.locator._toastContainer + + " span:contains(" + + toolTipOrToasttext + + ")", + ).length > 0 + ) { + this.GetElement( + this.locator._toastContainer + + ":has(:contains('" + + toolTipOrToasttext + + "'))", + ).then(($toastContainer) => { + $toastContainer.remove(); + cy.log(toolTipOrToasttext + " toast removed"); + }); + } + break; } }); } @@ -521,10 +578,10 @@ export class AggregateHelper extends ReusableHelper { this.Sleep(); //for selected value to reflect! } - public SelectDropdownList(ddName: string, dropdownOption: string) { - this.GetNClick(this.locator._existingFieldTextByName(ddName)); - cy.get(this.locator._dropdownText).contains(dropdownOption).click(); - } + // public SelectDropdownList(ddName: string, dropdownOption: string) { + // this.GetNClick(this.locator._existingFieldTextByName(ddName)); + // cy.get(this.locator._dropdownText).contains(dropdownOption).click(); + // } public SelectFromMultiSelect( options: string[], @@ -576,16 +633,19 @@ export class AggregateHelper extends ReusableHelper { // .click() } - public PressEscape() { + public PressEscape(sleep = 500) { cy.get("body").type("{esc}"); + this.Sleep(sleep); } - public PressEnter() { + public PressEnter(sleep = 500) { cy.get("body").type("{enter}"); + this.Sleep(sleep); } - public PressDelete() { + public PressDelete(sleep = 500) { cy.get("body").type(`{del}`, { force: true }); + this.Sleep(sleep); } public SelectAllWidgets(parentWidget = ".appsmith_widget_0") { @@ -596,8 +656,8 @@ export class AggregateHelper extends ReusableHelper { cy.get(this.locator._canvasViewport).invoke("width", `${width}px`); } - public ClickOutside() { - cy.get("body").click(0, 0, { force: true }); + public ClickOutside(x = 0, y = 0, force = true) { + cy.get("body").click(x, y, { force: force }); } public RemoveMultiSelectItems(items: string[]) { @@ -682,9 +742,14 @@ export class AggregateHelper extends ReusableHelper { force = false, waitTimeInterval = 500, ctrlKey = false, + metaKey = false, ) { return this.ScrollIntoView(selector, index) - .click({ force: force, ctrlKey: ctrlKey }) + .click({ + force: force, + ctrlKey: ctrlKey, + metaKey, + }) .wait(waitTimeInterval); } @@ -794,6 +859,11 @@ export class AggregateHelper extends ReusableHelper { this.TypeText(selector, totype, index); } } + public ClickNClear(selector: string, force = false, index = 0) { + this.GetNClick(selector, index, force); + this.ClearTextField(selector, force, index); + } + public ClearTextField(selector: string, force = false, index = 0) { this.GetElement(selector).eq(index).clear({ force }); this.Sleep(500); //for text to clear for CI runs @@ -873,7 +943,7 @@ export class AggregateHelper extends ReusableHelper { ) { return cy .get(selector) - .contains(containsText) + .contains(containsText, { matchCase: false }) .eq(index) .click({ force: force }) .wait(waitTimeInterval); @@ -894,19 +964,11 @@ export class AggregateHelper extends ReusableHelper { propertyName: string, toggle: "true" | "false", ) { - let locator; - if (propertyName.startsWith("//")) { - locator = cy.xpath(propertyName); - locator.should("have.attr", toggle); - } else if (propertyName.includes(" ")) { - locator = cy.get(propertyName); - locator.should("have.attr", toggle); - } else { - locator = cy.xpath(this.locator._propertyToggleValue(propertyName)); - locator.invoke("attr", "data-checked").then((classes) => { + this.GetElement(this.locator._propertyToggleValue(propertyName)) + .invoke("attr", "data-checked") + .then((classes) => { expect(classes).includes(toggle); }); - } } public AssertExistingCheckedState(selector: string, toggle = "true") { @@ -941,13 +1003,25 @@ export class AggregateHelper extends ReusableHelper { public AssertAttribute( selector: string, attribName: string, - attribValue: string, + attribValue: any, index = 0, ) { return this.GetElement(selector) .eq(index) .should("have.attr", attribName, attribValue); } + + public AssertProperty( + selector: string, + propName: string, + propValue: any, + index = 0, + ) { + return this.GetElement(selector) + .eq(index) + .should("have.prop", propName, propValue); + } + public AssertCSS( selector: string, cssName: string, @@ -1019,16 +1093,19 @@ export class AggregateHelper extends ReusableHelper { win.location.href = url; }); }); + this.AssertElementAbsence( + this.locator._specificToast("Cannot read properties of undefined"), + ); this.assertHelper.AssertDocumentReady(); - this.Sleep(2000); + this.Sleep(4000); //for page to load for CI runs networkCallAlias && this.assertHelper.AssertNetworkStatus("@" + networkCallAlias); //getWorkspace for Edit page! } public ActionContextMenuWithInPane({ action = "Delete", - subAction = "", entityType = EntityItems.JSObject, + subAction = "", toastToValidate = "", }: DeleteParams) { cy.get(this.locator._contextMenuInPane).click(); @@ -1174,9 +1251,9 @@ export class AggregateHelper extends ReusableHelper { setTimeout(() => { // Move cursor to the end of the line input.execCommand("goLineEnd"); - }, 300); - }, 300); - }, 300); + }, 1000); + }, 500); + }, 500); } else { input.focus(); this.Sleep(200); @@ -1186,7 +1263,7 @@ export class AggregateHelper extends ReusableHelper { this.Sleep(200); } }); - this.Sleep(500); //for value set to settle + this.Sleep(); //for value set to settle } public UpdateFieldInput(selector: string, value: string) { @@ -1509,6 +1586,14 @@ export class AggregateHelper extends ReusableHelper { return this.GetElement(selector).scrollTo(position).wait(2000); } + public ScrollToXY( + selector: ElementType, + x: number | string, + y: number | string, + ) { + return this.GetElement(selector).scrollTo(x, y).wait(2000); + } + public GetWidth(widgetSelector: string) { this.GetElement(widgetSelector).then(($element) => { cy.wrap(Number($element.width())).as("eleWidth"); @@ -1631,6 +1716,18 @@ export class AggregateHelper extends ReusableHelper { }); } + public GetAttribute(selector: string, attribName: string, index = 0) { + return this.GetElement(selector).eq(index).invoke("attr", attribName); + } + + public AssertClassExists(selector: string, className: string) { + this.GetElement(selector).should("have.class", className); + } + + public VerifySnapshot(selector: string, identifier: string) { + this.GetElement(selector).matchImageSnapshot(identifier); + } + //Not used: // private xPathToCss(xpath: string) { // return xpath diff --git a/app/client/cypress/support/Pages/ApiPage.ts b/app/client/cypress/support/Pages/ApiPage.ts index a60093d554..3087748f2e 100644 --- a/app/client/cypress/support/Pages/ApiPage.ts +++ b/app/client/cypress/support/Pages/ApiPage.ts @@ -64,7 +64,7 @@ export class ApiPage { _imageSrc = "//img/parent::div"; private _trashDelete = "[data-testid=t--trash-icon]"; private _onPageLoad = "input[name='executeOnLoad'][type='checkbox']"; - private _confirmBeforeRunningAPI = + private _confirmBeforeRunning = "input[name='confirmBeforeExecute'][type='checkbox']"; private _paginationTypeLabels = ".t--apiFormPaginationType label"; _saveAsDS = ".t--store-as-datasource"; @@ -88,10 +88,10 @@ export class ApiPage { ) { if (aftDSSaved) this.agHelper.GetNClick(this._createQuery); else { - this.agHelper.RemoveEvaluatedPopUp(); + this.agHelper.RemoveUIElement("EvaluatedPopUp"); this.agHelper.GetHoverNClick(this.locator._createNew); this.agHelper.GetNClick(this._blankAPI, 0, true); - this.agHelper.RemoveTooltip("Add a new query/JS Object"); + this.agHelper.RemoveUIElement("Tooltip", "Add a new query/JS Object"); } this.assertHelper.AssertNetworkStatus("@createNewApi", 201); @@ -242,10 +242,10 @@ export class ApiPage { else this.agHelper.CheckUncheck(this._onPageLoad, false); } - ToggleConfirmBeforeRunningApi(enable = true || false) { + ToggleConfirmBeforeRunning(enable = true || false) { this.SelectPaneTab("Settings"); - if (enable) this.agHelper.CheckUncheck(this._confirmBeforeRunningAPI, true); - else this.agHelper.CheckUncheck(this._confirmBeforeRunningAPI, false); + if (enable) this.agHelper.CheckUncheck(this._confirmBeforeRunning, true); + else this.agHelper.CheckUncheck(this._confirmBeforeRunning, false); } SelectPaneTab( diff --git a/app/client/cypress/support/Pages/AppSettings/AppSettings.ts b/app/client/cypress/support/Pages/AppSettings/AppSettings.ts index 5b3550e282..c94b181342 100644 --- a/app/client/cypress/support/Pages/AppSettings/AppSettings.ts +++ b/app/client/cypress/support/Pages/AppSettings/AppSettings.ts @@ -10,6 +10,7 @@ export class AppSettings { _generalSettingsHeader: "#t--general-settings-header", _embedSettingsHeader: "#t--share-embed-settings", _navigationSettingsTab: "#t--navigation-settings-header", + _importHeader: "#t--update-via-import", _navigationSettings: { _showNavbar: "#t--navigation-settings-show-navbar", _showSignIn: "#t--navigation-settings-show-sign-in", @@ -87,6 +88,10 @@ export class AppSettings { this.agHelper.GetNClick(this.locators._embedSettingsHeader); } + public GoToImport() { + this.agHelper.GetNClick(this.locators._importHeader); + } + public GoToPageSettings(pageName: string) { this.agHelper.GetNClick(this.locators._getPageSettingsHeader(pageName)); } @@ -116,6 +121,7 @@ export class AppSettings { customSlug?: string, editMode = true, ) { + appName = appName.replace(/\s+/g, "-"); this.agHelper.AssertElementAbsence(this.locators._updateStatus, 10000); cy.location("pathname").then((pathname) => { if (customSlug && customSlug.length > 0) { diff --git a/app/client/cypress/support/Pages/AppSettings/EmbedSettings.ts b/app/client/cypress/support/Pages/AppSettings/EmbedSettings.ts index a468eb286f..2e5ce8708e 100644 --- a/app/client/cypress/support/Pages/AppSettings/EmbedSettings.ts +++ b/app/client/cypress/support/Pages/AppSettings/EmbedSettings.ts @@ -1,4 +1,3 @@ -import { propPane } from "../../Objects/ObjectsCore"; import { ObjectsRegistry } from "../../Objects/Registry"; export class EmbedSettings { diff --git a/app/client/cypress/support/Pages/AppSettings/GeneralSettings.ts b/app/client/cypress/support/Pages/AppSettings/GeneralSettings.ts index fd848269ca..f8242ae734 100644 --- a/app/client/cypress/support/Pages/AppSettings/GeneralSettings.ts +++ b/app/client/cypress/support/Pages/AppSettings/GeneralSettings.ts @@ -26,8 +26,7 @@ export class GeneralSettings { (currentAppName as string).length, newAppName, ); - this.agHelper.PressEnter(); - this.agHelper.Sleep(); + this.agHelper.PressEnter(1000); this.assertHelper.AssertNetworkStatus("@updateApplication", 200); this.appSettings.CheckUrl(appNameToBeVerified, pageName); if (reset) { @@ -36,7 +35,7 @@ export class GeneralSettings { newAppName.length, currentAppName as string, ); - this.agHelper.PressEnter(); + this.agHelper.PressEnter(1000); this.assertHelper.AssertNetworkStatus("@updateApplication", 200); this.appSettings.CheckUrl(currentAppName as string, pageName); } diff --git a/app/client/cypress/support/Pages/AssertHelper.ts b/app/client/cypress/support/Pages/AssertHelper.ts index 2ca169ba3c..b8aa9d4561 100644 --- a/app/client/cypress/support/Pages/AssertHelper.ts +++ b/app/client/cypress/support/Pages/AssertHelper.ts @@ -14,7 +14,6 @@ export const EntityItems = { export type EntityItemsType = (typeof EntityItems)[keyof typeof EntityItems]; export class AssertHelper extends ReusableHelper { - private locator = ObjectsRegistry.CommonLocators; public _modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; public isMac = Cypress.platform === "darwin"; @@ -30,7 +29,7 @@ export class AssertHelper extends ReusableHelper { expect(doc.readyState).to.equal("complete"); }), ); - cy.window({ timeout: 60000 }).should("have.property", "onload"); + //cy.window({ timeout: 60000 }).should("have.property", "onload");//commenting to reduce time } public AssertDelete(entityType: EntityItemsType) { @@ -64,34 +63,84 @@ export class AssertHelper extends ReusableHelper { return aliasName; } - public WaitForNetworkCall(aliasName: string) { + public WaitForNetworkCall(aliasName: string, responseTimeout = 150000) { // cy.wait(aliasName).then(($apiCall: any) => { // expect($apiCall.response.body.responseMeta.status).to.eq(expectedStatus); // }); - // cy.wait(aliasName).should( - // "have.nested.property", - // "response.body.responseMeta.status", - // expectedStatus, - // ); - this.Sleep(2000); //Wait a bit for call to finish! - return cy.wait(this.GetAliasName(aliasName), { responseTimeout: 60000 }); + this.Sleep(); //wait a bit to avoid flaky tests + return cy + .wait(this.GetAliasName(aliasName), { timeout: responseTimeout }) + .then((interceptions) => { + return cy + .get(this.GetAliasName(aliasName), { timeout: responseTimeout }) + .its("response"); + }); } - public AssertNetworkStatus(aliasName: string, expectedStatus = 200) { - this.WaitForNetworkCall(aliasName); - cy.get(this.GetAliasName(aliasName)) - .its("response.body.responseMeta.status") - .should("eq", expectedStatus); - - //To improve below: - // cy.wait(aliasName, { timeout: timeout }).should((response: any) => { - // expect(response.status).to.be.oneOf([expectedStatus]); - // }); + public AssertNetworkStatus( + aliasName: string, + expectedStatus: number | number[] = 200, + waitForNetworkCall = true, + ) { + if (waitForNetworkCall) { + // If waitForNetworkCall is true, then use the response from WaitForNetworkCall call + return this.WaitForNetworkCall(aliasName).then((response: any) => + this.processNetworkStatus(response, expectedStatus), + ); + } else { + // If interception is not available, directly get the alias & use it + return cy + .get(this.GetAliasName(aliasName)) + .its("response") + .then((interception: any) => + this.processNetworkStatus(interception, expectedStatus), + ); + } } - public AssertNetworkExecutionSuccess(aliasName: string, expectedRes = true) { - this.WaitForNetworkCall(aliasName); + private processNetworkStatus( + response: any, + expectedStatus: number | number[], + ) { + const responseStatus = Number(response.body.responseMeta.status); + const expectedStatusArray = Array.isArray(expectedStatus) + ? expectedStatus + : [expectedStatus]; + + expect(expectedStatusArray).to.include(responseStatus); + return responseStatus; + } + + public AssertNetworkResponseData( + aliasName: string, + waitForNetworkCall = true, + ) { + if (waitForNetworkCall) { + // If waitForNetworkCall is true, then use the interception from received call + this.WaitForNetworkCall(aliasName).then((interception: any) => { + this.processNetworkResponseData(interception); + }); + } else { + // If interception is not available, directly get the alias & use it + cy.get(this.GetAliasName(aliasName)) + .its("response") + .then((interception: any) => { + this.processNetworkResponseData(interception); + }); + } + } + + private processNetworkResponseData(response: any) { + expect(response.body.data).to.not.be.empty; + } + + public AssertNetworkExecutionSuccess( + aliasName: string, + expectedRes = true, + waitForNetworkCall = true, + ) { + waitForNetworkCall && this.WaitForNetworkCall(aliasName); cy.get(aliasName) .its("response.body.data.isExecutionSuccess") .should("eq", expectedRes); diff --git a/app/client/cypress/support/Pages/CommunityTemplates.ts b/app/client/cypress/support/Pages/CommunityTemplates.ts new file mode 100644 index 0000000000..c33245fd34 --- /dev/null +++ b/app/client/cypress/support/Pages/CommunityTemplates.ts @@ -0,0 +1,73 @@ +import { ObjectsRegistry } from "../Objects/Registry"; + +// Edit mode modal +export class CommunityTemplates { + private agHelper = ObjectsRegistry.AggregateHelper; + public locators = { + _publishInitiateButton: "[data-testid='t--Publish-Initiate']", + _dialogBox: ".ads-v2-modal__content", + _communityForm: { + inputs: { + name: "[data-testid='t--community-template-name-input']", + excerpt: "[data-testid='t--community-template-excerpt-input']", + useCases: "[data-testid='t--community-template-usecases-input']", + }, + preview: { + name: "[data-testid='t--community-template-name-preview']", + excerpt: "[data-testid='t--community-template-excerpt-preview']", + useCases: "[data-testid='t--community-template-usecases-preview']", + }, + author: { + name: "[data-testid='t--community-template-author-name-input']", + email: "[data-testid='t--community-template-author-email-input']", + }, + appSettings: { + public: + "[data-testid='t--community-template-app-settting-public-switch']", + forkable: + "[data-testid='t--community-template-app-settting-forkable-switch']", + }, + submitBtn: "[data-testid='t--community-template-publish-submit-btn']", + tnCCheckbox: "[data-testid='t--community-template-tnc-checkbox']", + }, + }; + + AssertInputValueToEqualPreviewValue( + inputSelector: string, + previewSelector: string, + ) { + return this.agHelper.GetText(previewSelector).then((previewName) => { + this.agHelper.ValidateFieldInputValue( + inputSelector, + previewName as string, + ); + }); + } + + AssertPublishButtonState(disabled: boolean) { + return this.agHelper.AssertElementEnabledDisabled( + this.locators._communityForm.submitBtn, + 0, + disabled, + ); + } + + AssertChangeAuthorDetailsDisablesSubmit( + selector: string, + testUserName: string, + ) { + this.agHelper.GetText(selector, "val").then((authorName) => { + if (typeof authorName === "string" && authorName === "") { + this.AssertPublishButtonState(true); + this.agHelper.UpdateInputValue(selector, testUserName); + } + }); + } + + AssertDisablingAppSettingDisablesSubmit(selector: string) { + this.agHelper.CheckUncheck(selector, false); + this.AssertPublishButtonState(true); + this.agHelper.CheckUncheck(selector, true); + this.AssertPublishButtonState(false); + } +} diff --git a/app/client/cypress/support/Pages/DataSources.ts b/app/client/cypress/support/Pages/DataSources.ts index ab98587dff..91bedefd81 100644 --- a/app/client/cypress/support/Pages/DataSources.ts +++ b/app/client/cypress/support/Pages/DataSources.ts @@ -7,6 +7,7 @@ export const DataSourceKVP = { Mongo: "MongoDB", MySql: "MySQL", UnAuthenticatedGraphQL: "GraphQL API", + AuthenticatedGraph: "Authenticated GraphQL API", MsSql: "Microsoft SQL Server", Airtable: "Airtable", ArangoDB: "ArangoDB", @@ -15,6 +16,8 @@ export const DataSourceKVP = { Redis: "Redis", Oracle: "Oracle", S3: "S3", + Twilio: "Twilio", + SMTP: "SMTP", }; //DataSources KeyValuePair export enum Widgets { @@ -23,6 +26,7 @@ export enum Widgets { Chart, Text, } +type AppModes = "Edit" | "View"; interface RunQueryParams { toValidateResponse?: boolean; @@ -51,7 +55,8 @@ export class DataSources { private _addNewDataSource = ".t--entity-add-btn.datasources button"; private _createNewPlgin = (pluginName: string) => ".t--plugin-name:contains('" + pluginName + "')"; - public _host = "input[name$='.datasourceConfiguration.endpoints[0].host']"; + public _host = (index = "0") => + "input[name$='.datasourceConfiguration.endpoints[" + index + "].host']"; public _port = "input[name$='.datasourceConfiguration.endpoints[0].port']"; public _databaseName = "input[name$='.datasourceConfiguration.authentication.databaseName']"; @@ -67,7 +72,6 @@ export class DataSources { private defaultDatabaseName = "input[name*='datasourceConfiguration.connection.defaultDatabaseName']"; private _testDs = ".t--test-datasource"; - _saveAndAuthorizeDS = ".t--save-and-authorize-datasource"; _saveDs = ".t--save-datasource"; _datasourceCard = ".t--datasource"; _dsMenuoptions = "div.t--datasource-menu-option"; @@ -78,6 +82,8 @@ export class DataSources { _activeDS = "[data-testid='active-datasource-name']"; _mockDatasourceName = "[data-testid=mockdatasource-name]"; _templateMenu = ".t--template-menu"; + _addSuggestedExisting = "t--suggested-widget-existing"; + _addSuggestedAddNew = "t--suggested-widget-add-new"; _templateMenuOption = (action: string) => "//div[contains(@class, 't--template-menu')]//div[text()='" + action + "']"; _createQuery = ".t--create-query"; @@ -114,7 +120,7 @@ export class DataSources { _generatePageBtn = "[data-testid=t--generate-page-form-submit]"; _selectedRow = ".tr.selected-row"; _activeTab = "span:contains('Active')"; - _selectedActiveTab = "li[aria-selected='true'] " + this._activeTab; + _selectedActiveTab = "button[aria-selected='true'] " + this._activeTab; _contextMenuDSReviewPage = "[data-testid='t--context-menu-trigger']"; _contextMenuDelete = ".t--datasource-option-delete"; _datasourceCardGeneratePageBtn = ".t--generate-template"; @@ -145,7 +151,7 @@ export class DataSources { `//div/span[text()='Result:']/span[number(substring-before(normalize-space(text()), ' Record')) >= ${recordCount}]`; _noRecordFound = "span[data-testid='no-data-table-message']"; _usePreparedStatement = - "input[name='actionConfiguration.pluginSpecifiedTemplates[0].value'][type='checkbox']"; + "input[name='actionConfiguration.pluginSpecifiedTemplates[0].value'][type='checkbox'], input[name='actionConfiguration.formData.preparedStatement.data'][type='checkbox']"; _queriesOnPageText = (dsName: string) => ".t--datasource-name:contains('" + dsName + "') .t--queries-for-DB"; _mockDB = (dbName: string) => @@ -184,8 +190,15 @@ export class DataSources { _getStructureReq = "/api/v1/datasources/*/structure?ignoreCache=true"; _editDatasourceFromActiveTab = (dsName: string) => ".t--datasource-name:contains('" + dsName + "')"; - private _suggestedWidget = (widgetType: string) => - ".t--suggested-widget-" + widgetType + ""; + _mandatoryMark = "//span[text()='*']"; + _deleteDSHostPort = ".t--delete-field"; + + private _suggestedWidget = (widgetType: string, parentClass: string) => + "//div[contains(@class, '" + + parentClass + + "')]//div[contains(@class, 't--suggested-widget-" + + widgetType + + "')]"; private _curlTextArea = "//label[text()='Paste CURL Code Here']/parent::form/div"; @@ -215,6 +228,7 @@ export class DataSources { public _datasourceModalDoNotSave = ".t--datasource-modal-do-not-save"; public _cancelEditDatasourceButton = ".t--cancel-edit-datasource"; public _urlInputControl = "input[name='url']"; + public _headerKey = "input[name='headers[0].key']"; public _mongoCollectionPath = "t--actionConfiguration.formData.collection"; _getJSONswitchLocator = (fieldName: string) => "//p[contains(text(),'" + @@ -243,7 +257,7 @@ export class DataSources { private _datasourceSchemaRefreshBtn = ".datasourceStructure-refresh"; private _datasourceStructureHeader = ".datasourceStructure-header"; private _datasourceColumnSchemaInQueryEditor = ".t--datasource-column"; - private _datasourceStructureSearchInput = ".datasourceStructure-search input"; + _datasourceStructureSearchInput = ".datasourceStructure-search input"; _jsModeSortingControl = ".t--actionConfiguration\\.formData\\.sortBy\\.data"; public _queryEditorCollapsibleIcon = ".collapsible-icon"; _globalSearchTrigger = ".t--global-search-modal-trigger"; @@ -265,8 +279,28 @@ export class DataSources { _s3EditFileName = "[data-widgetname-cy='update_file_name'] div[data-testid='input-container']"; _s3MaxFileSizeAlert = "//p[@role='alert']"; + _entityExplorerID = (dsName: string) => + "[data-testid='t--entity-item-" + dsName + "']"; + _stagingTab = "[data-testid='t--ds-data-filter-Staging']"; + _graphQlDsFromRightPane = (dsName: string) => + "//div/span[text() ='" + dsName + "']"; + _imgFireStoreLogo = "//img[contains(@src, 'firestore.svg')]"; + private _dsVirtuosoElement = (dsName: string) => + `[data-testid='t--entity-item-${dsName}'] + div .t--schema-virtuoso-container`; + private _dsVirtuosoList = `[data-test-id="virtuoso-item-list"]`; + private _dsVirtuosoElementTable = (targetTableName: string) => + `.t--entity-item[data-testid='t--entity-item-${targetTableName}']`; + private _dsPageTabListItem = (buttonText: string) => + `//div[contains(@class, 't--datasource-tab-list')]/button/span[text()='${buttonText}']`; + _dsPageTabContainerTableName = (tableName: string) => + `.t--datasource-tab-container ${this._entityExplorerID(tableName)}`; + _dsPageTableTriggermenuTarget = (tableName: string) => + `${this._dsPageTabContainerTableName(tableName)} .t--template-menu-trigger`; + _gSheetQueryPlaceholder = ".CodeMirror-placeholder"; + _dsNameInExplorer = (dsName: string) => + `div.t--entity-name:contains('${dsName}')`; - public AssertDSEditViewMode(mode: "Edit" | "View") { + public AssertDSEditViewMode(mode: AppModes) { if (mode == "Edit") this.agHelper.AssertElementAbsence(this._editButton); else if (mode == "View") this.agHelper.AssertElementExist(this._editButton); } @@ -284,7 +318,7 @@ export class DataSources { ).click(); this.agHelper.GetNClick(this._generatePageBtn); this.assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201); - this.agHelper.GetNClick(this.locator._visibleTextSpan("Got it")); + this.agHelper.ClickButton("Got it"); } public GeneratePageWithMockDB() { @@ -299,9 +333,9 @@ export class DataSources { this.assertHelper.AssertNetworkStatus("@getDatasourceStructure"); //Making sure table dropdown is populated this.agHelper.GetNClick(this._selectTableDropdown, 0, true); this.agHelper.GetNClickByContains(this._dropdownOption, "public.users"); - this.agHelper.GetNClick(this._generatePageBtn); + this.agHelper.GetNClick(this._generatePageBtn, 0, true); this.assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201); - this.agHelper.GetNClick(this.locator._visibleTextSpan("Got it")); + this.agHelper.ClickButton("Got it"); } public StartDataSourceRoutes() { @@ -416,7 +450,7 @@ export class DataSources { this.agHelper.GetNClick(this._addNewDataSource, 0, true); this.agHelper.Sleep(); }); - this.agHelper.RemoveTooltip("Add a new datasource"); + this.agHelper.RemoveUIElement("Tooltip", "Add a new datasource"); cy.get(this._newDatasourceContainer).scrollTo("bottom", { ensureScrollable: false, }); @@ -448,7 +482,7 @@ export class DataSources { this._port, this.dataManager.dsValues[environment].postgres_port.toString(), ); - this.agHelper.UpdateInputValue(this._host, hostAddress); + this.agHelper.UpdateInputValue(this._host(), hostAddress); this.agHelper.ClearNType(this._databaseName, databaseName); cy.get(this._username).type( username == "" @@ -487,14 +521,14 @@ export class DataSources { ? this.dataManager.dsValues[environment].oracle_host + " " : this.dataManager.dsValues[environment].oracle_host; const databaseName = shouldAddTrailingSpaces - ? this.dataManager.dsValues[environment].oracle_name + " " - : this.dataManager.dsValues[environment].oracle_name; - this.agHelper.UpdateInputValue(this._host, hostAddress); + ? this.dataManager.dsValues[environment].oracle_service + " " + : this.dataManager.dsValues[environment].oracle_service; + this.agHelper.UpdateInputValue(this._host(), hostAddress); this.agHelper.UpdateInputValue( this._port, this.dataManager.dsValues[environment].oracle_port.toString(), ); - cy.get(this._databaseName).clear().type(databaseName); + cy.get(this._databaseName).type(databaseName); cy.get(this._username).type( username == "" ? this.dataManager.dsValues[environment].oracle_username @@ -514,15 +548,16 @@ export class DataSources { const hostAddress = shouldAddTrailingSpaces ? this.dataManager.dsValues[environment].mongo_host + " " : this.dataManager.dsValues[environment].mongo_host; - this.agHelper.UpdateInputValue(this._host, hostAddress); + this.agHelper.UpdateInputValue(this._host(), hostAddress); this.agHelper.UpdateInputValue( this._port, this.dataManager.dsValues[environment].mongo_port.toString(), ); - this.agHelper.ClearNType( - this._databaseName, - this.dataManager.dsValues[environment].mongo_databaseName, - ); + this.agHelper.ClearTextField(this._databaseName); + const databaseName = shouldAddTrailingSpaces + ? this.dataManager.dsValues[environment].mongo_databaseName + " " + : this.dataManager.dsValues[environment].mongo_databaseName; + this.agHelper.TypeText(this._databaseName, databaseName); } public FillMySqlDSForm( @@ -536,7 +571,7 @@ export class DataSources { ? this.dataManager.dsValues[environment].mysql_databaseName + " " : this.dataManager.dsValues[environment].mysql_databaseName; - this.agHelper.UpdateInputValue(this._host, hostAddress); + this.agHelper.UpdateInputValue(this._host(), hostAddress); this.agHelper.UpdateInputValue( this._port, this.dataManager.dsValues[environment].mysql_port.toString(), @@ -551,16 +586,26 @@ export class DataSources { ); } - public FillMsSqlDSForm(environment = this.dataManager.defaultEnviorment) { + public FillMsSqlDSForm( + environment = this.dataManager.defaultEnviorment, + leaveDBNameEmpty = true, + ) { this.agHelper.UpdateInputValue( - this._host, + this._host(), this.dataManager.dsValues[environment].mssql_host, ); this.agHelper.UpdateInputValue( this._port, this.dataManager.dsValues[environment].mssql_port.toString(), ); - this.agHelper.ClearTextField(this._databaseName); + + if (leaveDBNameEmpty) { + this.agHelper.ClearTextField(this._databaseName); + } else { + const databaseName = + this.dataManager.dsValues[environment].mssql_databaseName; + this.agHelper.ClearNType(this._databaseName, databaseName); + } // this.agHelper.UpdateInputValue( // this._databaseName, // datasourceFormData["mssql-databaseName"], @@ -592,7 +637,7 @@ export class DataSources { public FillArangoDSForm(environment = this.dataManager.defaultEnviorment) { this.agHelper.UpdateInputValue( - this._host, + this._host(), this.dataManager.dsValues[environment].arango_host, ); this.agHelper.UpdateInputValue( @@ -651,7 +696,9 @@ export class DataSources { // ); this.agHelper.UpdateFieldInput( this.locator._inputFieldByName("Service account credentials"), - JSON.stringify(Cypress.env("FIRESTORE_PRIVATE_KEY")), + JSON.stringify( + this.dataManager.dsValues[environment].firestore_serviceaccountkey, + ), ); //}); } @@ -660,7 +707,7 @@ export class DataSources { environment = this.dataManager.defaultEnviorment, ) { this.agHelper.UpdateInputValue( - this._host, + this._host(), this.dataManager.dsValues[environment].elastic_host, ); this.agHelper.UpdateInputValue( @@ -679,12 +726,32 @@ export class DataSources { public FillUnAuthenticatedGraphQLDSForm( environment = this.dataManager.defaultEnviorment, + enterOrSelectUrl: "enter" | "select" = "enter", + dsNameToSelect = "", ) { this.agHelper.GetNClick(this._createBlankGraphQL); - this.apiPage.EnterURL( + cy.get("@guid").then((uid) => { + this.agHelper.RenameWithInPane("GraphQL_API" + "_" + uid, true); + + if (enterOrSelectUrl == "enter") + this.apiPage.EnterURL( + this.dataManager.dsValues[environment].GraphqlApiUrl_TED, + ); + else if (enterOrSelectUrl == "select") + this.agHelper.GetNClick(this._graphQlDsFromRightPane(dsNameToSelect)); + + this.assertHelper.AssertNetworkStatus("@createNewApi", 201); + cy.wrap("GraphQL_API" + "_" + uid).as("dsName"); + }); + } + + public FillAuthenticatedGrapgQLURL( + environment = this.dataManager.defaultEnviorment, + ) { + this.agHelper.TypeText( + this.locator._inputFieldByName("URL") + "//" + this.locator._inputField, this.dataManager.dsValues[environment].GraphqlApiUrl_TED, ); - this.assertHelper.AssertNetworkStatus("@createNewApi", 201); } public CreateNFillAuthenticatedGraphQLDSForm( @@ -693,12 +760,7 @@ export class DataSources { hValue: string, environment = this.dataManager.defaultEnviorment, ) { - this.NavigateToDSCreateNew(); - this.CreatePlugIn("Authenticated GraphQL API"); - this.agHelper.TypeText( - this.locator._inputFieldByName("URL") + "//" + this.locator._inputField, - this.dataManager.dsValues[environment].GraphqlApiUrl_TED, - ); + this.FillAuthenticatedGrapgQLURL(environment); this.agHelper.UpdateInputValue(this._graphQLHeaderKey, hKey); this.agHelper.UpdateInputValue(this._graphQLHeaderValue, hValue); @@ -712,7 +774,7 @@ export class DataSources { public FillRedisDSForm(environment = this.dataManager.defaultEnviorment) { this.agHelper.UpdateInputValue( - this._host, + this._host(), this.dataManager.dsValues[environment].redis_host, ); this.agHelper.UpdateInputValue( @@ -732,9 +794,21 @@ export class DataSources { ); } - public TestSaveDatasource(expectedRes = true, isForkModal = false) { + public FillTwilioDSForm(environment = this.dataManager.defaultEnviorment) { + this.ValidateNSelectDropdown("Authentication type", "", "Basic auth"); + this.agHelper.UpdateInputValue( + this._username, + this.dataManager.dsValues[environment].twilio_username.toString(), + ); + this.agHelper.UpdateInputValue( + this._password, + this.dataManager.dsValues[environment].twilio_password.toString(), + ); + } + + public TestSaveDatasource(expectedRes = true, isReconnectModal = false) { this.TestDatasource(expectedRes); - this.SaveDatasource(isForkModal); + this.SaveDatasource(isReconnectModal); } public TestDatasource(expectedRes = true) { @@ -746,25 +820,24 @@ export class DataSources { } } - public SaveDatasource(isForkModal = false, isSavingEnvInOldDS = false) { + public SaveDatasource(isReconnectModal = false, isSavingEnvInOldDS = false) { this.agHelper.Sleep(500); //bit of time for CI! this.agHelper.GetNClick(this._saveDs); - if (!isForkModal) { + if (!isReconnectModal) { this.assertHelper.AssertNetworkStatus("@saveDatasource", 201); if (!isSavingEnvInOldDS) this.agHelper.AssertContains("datasource created"); } else { this.assertHelper.AssertNetworkStatus("@updateDatasource", 200); } + } - // cy.wait("@saveDatasource") - // .then((xhr) => { - // cy.log(JSON.stringify(xhr.response!.body)); - // }).should("have.nested.property", "response.body.responseMeta.status", 200); + public AssertSaveDSButtonDisability(isDisabled = true) { + this.agHelper.AssertElementEnabledDisabled(this._saveDs, 0, isDisabled); } public AuthAPISaveAndAuthorize() { - cy.get(this._saveAndAuthorizeDS).click(); + cy.get(this._saveDs).click(); this.assertHelper.AssertNetworkStatus("@saveDatasource", 201); } @@ -774,8 +847,24 @@ export class DataSources { this.agHelper.AssertContains("datasource updated"); } + public ShowAllDatasources() { + this.agHelper.GetElement(this.locator._body).then(($body) => { + if ($body.find(this._selectedActiveTab).length === 0) { + this.agHelper.ClickButton("Show all datasources"); + } + }); + } + public ClickActiveTabDSContextMenu(datasourceName: string) { - this.NavigateToActiveTab(); + this.agHelper.GetElement(this.locator._body).then(($body) => { + if ( + $body.find(this.locator._visibleTextSpan("Show all datasources", true)) + .length !== 0 + ) { + this.ShowAllDatasources(); + } else this.NavigateToActiveTab(); + }); + cy.get(this._datasourceCard) .contains(datasourceName) .parents(this._datasourceCard) @@ -787,7 +876,7 @@ export class DataSources { public DeleteDatasouceFromActiveTab( datasourceName: string, - expectedRes = 200 || 409 || [200 | 409], + expectedRes = 200 || 409 || [200, 409], ) { this.ClickActiveTabDSContextMenu(datasourceName); this.agHelper.GetNClick(this._dsOptionMenuItem("Delete"), 0, false, 200); @@ -795,9 +884,9 @@ export class DataSources { this.ValidateDSDeletion(expectedRes); } - public DeleteDatasouceFromWinthinDS( + public DeleteDatasourceFromWithinDS( datasourceName: string, - expectedRes: number | number[] = 200 || 409 || [200 | 409], + expectedRes: number | number[] = 200 || 409 || [200, 409], ) { this.NavigateToActiveTab(); cy.get(this._datasourceCard) @@ -825,7 +914,7 @@ export class DataSources { } public DeleteDSDirectly( - expectedRes: number | number[] = 200 || 409 || [200 | 409], + expectedRes: number | number[] = 200 || 409 || [200, 409], toNavigateToDSInfoPage = true, ) { toNavigateToDSInfoPage && @@ -850,25 +939,20 @@ export class DataSources { } public ValidateDSDeletion(expectedRes: number | number[] = 200) { - let toValidateRes = expectedRes == 200 || expectedRes == 409 ? true : false; - if (toValidateRes) { - if (expectedRes == 200) - this.agHelper.AssertContains("datasource deleted successfully"); - else this.agHelper.AssertContains("action(s) using it."); - this.assertHelper.AssertNetworkStatus( - "@deleteDatasource", - expectedRes as number, - ); - } else { - cy.wait("@deleteDatasource") - .its("response.body.responseMeta.status") - .should("be.oneOf", [200, 409]); - } + this.assertHelper + .AssertNetworkStatus("@deleteDatasource", expectedRes) + .then((responseStatus) => { + this.agHelper.AssertContains( + responseStatus === 200 + ? "datasource deleted successfully" + : "action(s) using it", + ); + }); } public NavigateToActiveTab() { this.agHelper.GetElement(this.locator._body).then(($body) => { - if ($body.find(this._selectedActiveTab).length == 0) { + if ($body.find(this._selectedActiveTab).length === 0) { this.NavigateToDSCreateNew(); this.agHelper.GetNClick(this._activeTab, 0, true); } @@ -885,7 +969,7 @@ export class DataSources { ? this._createQuery : this._datasourceCardGeneratePageBtn; - this.AssertDSActive(new RegExp("^" + datasourceName + "$")) //This regex is to exact match the datasource name + this.AssertDSInActiveList(new RegExp("^" + datasourceName + "$")) //This regex is to exact match the datasource name .scrollIntoView() .should("be.visible") .then(($element) => { @@ -902,7 +986,7 @@ export class DataSources { this.assertHelper.AssertNetworkStatus("@getDatasourceStructure", 200); //Making sure table dropdown is populated } - public AssertDSActive(dsName: string | RegExp) { + public AssertDSInActiveList(dsName: string | RegExp) { this.entityExplorer.NavigateToSwitcher("Explorer", 0, true); this.entityExplorer.ExpandCollapseEntity("Datasources", false); //this.entityExplorer.SelectEntityByName(datasourceName, "Datasources"); @@ -1017,7 +1101,7 @@ export class DataSources { if (dsName == "PostgreSQL") this.FillPostgresDSForm(); else if (dsName == "MySQL") this.FillMySqlDSForm(); else if (dsName == "MongoDB") this.FillMongoDSForm(); - this.SaveDatasource(true); + this.TestSaveDatasource(true, true); this.assertHelper.AssertNetworkStatus("@getPage", 200); this.assertHelper.AssertNetworkStatus("getWorkspace"); } @@ -1146,17 +1230,13 @@ export class DataSources { }); } - public ToggleUsePreparedStatement(enable = true || false) { - if (enable) - cy.get(this._usePreparedStatement).check({ - force: true, - }); - else - cy.get(this._usePreparedStatement).uncheck({ - force: true, - }); - - this.agHelper.AssertAutoSave(); + ToggleUsePreparedStatement( + enable = true || false, + toNavigateToSettings = false, + ) { + toNavigateToSettings && this.apiPage.SelectPaneTab("Settings"); + if (enable) this.agHelper.CheckUncheck(this._usePreparedStatement, true); + else this.agHelper.CheckUncheck(this._usePreparedStatement, false); } public EnterQuery(query: string, sleep = 500, toVerifySave = true) { @@ -1194,6 +1274,7 @@ export class DataSources { | "Mongo" | "MySql" | "UnAuthenticatedGraphQL" + | "AuthenticatedGraph" | "MsSql" | "Airtable" | "ArangoDB" @@ -1201,7 +1282,8 @@ export class DataSources { | "Elasticsearch" | "Redis" | "Oracle" - | "S3", + | "S3" + | "Twilio", navigateToCreateNewDs = true, testNSave = true, environment = this.dataManager.defaultEnviorment, @@ -1250,15 +1332,19 @@ export class DataSources { else if (DataSourceKVP[dsType] == "Redis") this.FillRedisDSForm(environment); else if (DataSourceKVP[dsType] == "S3") this.FillS3DSForm(); + else if (DataSourceKVP[dsType] == "Twilio") this.FillTwilioDSForm(); + else if (DataSourceKVP[dsType] == "Authenticated GraphQL API") + this.FillAuthenticatedGrapgQLURL(); if (testNSave) { this.TestSaveDatasource(); } else { this.SaveDatasource(); } - } else if (DataSourceKVP[dsType] == "GraphQL API") + cy.wrap(dataSourceName).as("dsName"); + } else if (DataSourceKVP[dsType] == "GraphQL API") { this.FillUnAuthenticatedGraphQLDSForm(environment); - cy.wrap(dataSourceName).as("dsName"); + } }); } @@ -1268,7 +1354,7 @@ export class DataSources { queryName = "", sleep = 500, ) { - this.agHelper.RemoveEvaluatedPopUp(); //to close the evaluated pop-up + this.agHelper.RemoveUIElement("EvaluatedPopUp"); //to close the evaluated pop-up this.entityExplorer.CreateNewDsQuery(dsName); if (query) { this.EnterQuery(query, sleep); @@ -1413,16 +1499,12 @@ export class DataSources { public FilterAndVerifyDatasourceSchemaBySearch( search: string, - filterBy?: "table" | "column", + expectedTableName = search, ) { this.agHelper.Sleep(2500); //for query editor to load this.agHelper.TypeText(this._datasourceStructureSearchInput, search); - this.agHelper.Sleep(); //for search result to load - if (filterBy === "column") { - this.VerifyColumnSchemaOnQueryEditor(search); - } else if (filterBy === "table") { - this.VerifyTableSchemaOnQueryEditor(search); - } + this.agHelper.Sleep(1000); //for search result to load + this.VerifyTableSchemaOnQueryEditor(expectedTableName); } public AssertDSDialogVisibility(isVisible = true) { @@ -1586,7 +1668,7 @@ export class DataSources { // save datasource this.agHelper.Sleep(500); - this.agHelper.GetNClick(this._saveAndAuthorizeDS); + this.agHelper.GetNClick(this._saveDs); //Accept consent this.agHelper.GetNClick(this._consent); @@ -1650,17 +1732,24 @@ export class DataSources { ); } - public AddSuggestedWidget(widget: Widgets, force = false, index = 0) { + public AddSuggestedWidget( + widget: Widgets, + parentClass = this._addSuggestedAddNew, + force = false, + index = 0, + ) { switch (widget) { case Widgets.Dropdown: - this.agHelper.GetNClick(this._suggestedWidget("SELECT_WIDGET")); + this.agHelper.GetNClick( + this._suggestedWidget("SELECT_WIDGET", parentClass), + ); this.agHelper.AssertElementVisibility( this.locator._widgetInCanvas(WIDGET.SELECT), ); break; case Widgets.Table: this.agHelper.GetNClick( - this._suggestedWidget("TABLE_WIDGET_V2"), + this._suggestedWidget("TABLE_WIDGET_V2", parentClass), index, force, ); @@ -1669,13 +1758,17 @@ export class DataSources { ); break; case Widgets.Chart: - this.agHelper.GetNClick(this._suggestedWidget("CHART_WIDGET")); + this.agHelper.GetNClick( + this._suggestedWidget("CHART_WIDGET", parentClass), + ); this.agHelper.AssertElementVisibility( this.locator._widgetInCanvas(WIDGET.CHART), ); break; case Widgets.Text: - this.agHelper.GetNClick(this._suggestedWidget("TEXT_WIDGET")); + this.agHelper.GetNClick( + this._suggestedWidget("TEXT_WIDGET", parentClass), + ); this.agHelper.AssertElementVisibility( this.locator._widgetInCanvas(WIDGET.TEXT), ); @@ -1826,4 +1919,86 @@ export class DataSources { ); }); } + + public AssertTableInVirtuosoList( + dsName: string, + targetTableName: string, + presence = true, + ) { + const ds_entity_name = dsName.replace(/\s/g, "_"); + this.entityExplorer.ExpandCollapseEntity("Datasources"); + cy.get(this.locator._body).then(($body: any) => { + if ($body.find(this._dsNameInExplorer(dsName)).length > 0) { + this.entityExplorer.ExpandCollapseEntity(dsName); + cy.intercept("GET", "/api/v1/datasources/*/structure?ignoreCache=*").as( + `getDatasourceStructureUpdated_${ds_entity_name}`, + ); + this.entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: dsName, + action: "Refresh", + }); + + this.assertHelper + .WaitForNetworkCall( + `@getDatasourceStructureUpdated_${ds_entity_name}`, + ) + .then(async (response) => { + const tables: any[] = response?.body.data?.tables || []; + const indexOfTable = tables.findIndex( + (table) => table.name === targetTableName, + ); + if (presence) { + this.agHelper.Sleep(); + this.agHelper + .GetNClick(this._dsVirtuosoElement(dsName)) + .then((parentElement) => { + const heightOfParentElement = + parentElement.outerHeight() || 0; + + // Every element (tables in this scenario) in the virtual list has equal heights. Assumption: Every table element accordion is collapsed by default. + const containerElement = parentElement.find( + this._dsVirtuosoList, + ); + const elementHeight = parseInt( + containerElement + .children() + .first() + .attr("data-known-size") || "", + 10, + ); + // Total height of the parent container holding the tables in the dom normally without virtualization rendering + const totalScroll = tables.length * elementHeight; + cy.log( + JSON.stringify({ heightOfParentElement, totalScroll }), + ); + if (heightOfParentElement < totalScroll) { + // Index of the table present in the array of tables which will determine the presence of element inside the parent container + let offset = indexOfTable * elementHeight; + const scrollPercent = Math.max( + (offset / (totalScroll || 1)) * 100, + 0, + ); + if (scrollPercent > 0) { + this.agHelper.ScrollToXY( + this._dsVirtuosoElement(dsName), + 0, + `${scrollPercent}%`, + ); + } + } + this.agHelper.AssertElementVisibility( + this._dsVirtuosoElementTable(targetTableName), + ); + }); + } else { + expect(indexOfTable).to.equal(-1); + } + }); + } + }); + } + + public selectTabOnDatasourcePage(tab: "View data" | "Configurations") { + this.agHelper.GetNClick(this._dsPageTabListItem(tab)); + } } diff --git a/app/client/cypress/support/Pages/DebuggerHelper.ts b/app/client/cypress/support/Pages/DebuggerHelper.ts index 6e2aef875b..6b43449909 100644 --- a/app/client/cypress/support/Pages/DebuggerHelper.ts +++ b/app/client/cypress/support/Pages/DebuggerHelper.ts @@ -46,6 +46,12 @@ export class DebuggerHelper { _intercomOption: "#intercom-trigger", _intercomConsentText: "[data-testid='t--intercom-consent-text']", _logsTab: "[data-testid='t--tab-LOGS_TAB']", + _debuggerFilterClear: + "//input[@data-testid='t--debugger-search']/following-sibling::span", + _logsGroup: "[data-testid='t--log-filter']", + _logGroupOption: (option: string) => + `[data-testid='t--log-filter-${option}']`, + _downStreamLogMessage: ".t--debugger-log-downstream-message", }; ClickDebuggerIcon( @@ -156,6 +162,11 @@ export class DebuggerHelper { this.agHelper.GetNAssertContains(this.locators._errorCount, count); } + changeLogsGroup(option: string) { + this.agHelper.GetNClick(this.locators._logsGroup); + this.agHelper.GetNClick(this.locators._logGroupOption(option)); + } + ClearLogs() { this.agHelper.GetNClick(this.locators._clearLogs); } @@ -232,4 +243,18 @@ export class DebuggerHelper { this.locators._debuggerList, ); } + + AssertDownStreamLogError(message: string, shouldOpenDebugger = true) { + if (shouldOpenDebugger) { + this.ClickDebuggerIcon(); + } + + this.agHelper.GetNClick(this.commonLocators._responseTab, 0, true, 0); + + this.agHelper + .GetText(this.locators._downStreamLogMessage, "text", 0) + .then(($text) => { + expect($text).to.contains(message); + }); + } } diff --git a/app/client/cypress/support/Pages/DeployModeHelper.ts b/app/client/cypress/support/Pages/DeployModeHelper.ts index afbd6b5eb4..0ab45878ed 100644 --- a/app/client/cypress/support/Pages/DeployModeHelper.ts +++ b/app/client/cypress/support/Pages/DeployModeHelper.ts @@ -30,9 +30,6 @@ export class DeployMode { `//div[@title='${option}']//input[@type='checkbox']/ancestor::div[@title='${option}']`; private _backtoHome = ".t--back-to-home"; private _homeAppsmithImage = "a.t--appsmith-logo"; - public envInfoModal = `[data-testid="t--env-info-modal"]`; - public envInfoModalDismissCheckbox = `[data-testid="t--env-info-dismiss-checkbox"]`; - public envInfoModalDeployButton = `[data-testid="t--env-info-modal-deploy-button"]`; //refering PublishtheApp from command.js public DeployApp( @@ -40,28 +37,16 @@ export class DeployMode { toCheckFailureToast = true, toValidateSavedState = true, addDebugFlag = true, - assertEnvInfoModal?: "present" | "absent", - dismissModal = false, ) { //cy.intercept("POST", "/api/v1/applications/publish/*").as("publishAppli"); // Wait before publish - this.agHelper.Sleep(3000); //wait for elements settle! + this.agHelper.Sleep(); //wait for elements settle! toValidateSavedState && this.agHelper.AssertAutoSave(); // Stubbing window.open to open in the same tab this.assertHelper.AssertDocumentReady(); this.StubbingDeployPage(addDebugFlag); this.agHelper.ClickButton("Deploy"); - if (!!assertEnvInfoModal && assertEnvInfoModal === "present") { - this.agHelper.WaitUntilEleAppear(this.envInfoModal); - this.agHelper.AssertElementExist(this.envInfoModal); - if (dismissModal) { - this.agHelper.CheckUncheck(this.envInfoModalDismissCheckbox); - } - } else { - this.agHelper.AssertElementAbsence(this.envInfoModal); - } - this.agHelper.GetNClickIfPresent(this.envInfoModalDeployButton); this.agHelper.AssertElementAbsence(this.locator._btnSpinner, 10000); //to make sure we have started navigation from Edit page //cy.get("@windowDeployStub").should("be.calledOnce"); this.assertHelper.AssertDocumentReady(); @@ -86,8 +71,8 @@ export class DeployMode { } // Stubbing window.open to open in the same tab - public StubbingWindow() { - cy.window({ timeout: 60000 }).then((window: any) => { + public StubbingWindow(timeout = 60000) { + cy.window({ timeout }).then((window: any) => { cy.stub(window, "open") .as("windowStub") .callsFake((url) => { @@ -138,25 +123,35 @@ export class DeployMode { networkCall: string, ) { this.StubbingWindow(); - this.agHelper.GetNClick(selector, 0, false, 4000); //timeout new url to settle loading - cy.window().then((win) => { - win.location.reload(); - }); //only reload page to get new url + this.agHelper.GetNClick(selector, 0, false, 0); + // cy.window().then((win) => { + // win.location.reload(); + // }); + this.agHelper.Sleep(4000); //Waiting a bit for new url to settle loading + // cy.url().then((url) => { + // cy.window().then((window) => { + // window.location.href = url; + // }); //only reload page to get new url + // }); cy.get("@windowStub").should("be.calledOnce"); cy.url().should("contain", expectedUrl); - this.assertHelper.AssertDocumentReady(); + this.agHelper.Sleep(2000); //stay in the page a bit before navigating back + //this.assertHelper.AssertDocumentReady(); cy.window({ timeout: 60000 }).then((win) => { win.history.back(); }); - this.assertHelper.AssertNetworkStatus("@" + networkCall); + this.assertHelper.AssertNetworkResponseData("@" + networkCall); this.assertHelper.AssertDocumentReady(); } - public NavigateBacktoEditor() { + public NavigateBacktoEditor(toastToCheck = "") { this.assertHelper.AssertDocumentReady(); this.agHelper.GetNClick(this.locator._backToEditor, 0, true); this.agHelper.Sleep(); localStorage.setItem("inDeployedMode", "false"); + if (toastToCheck) { + this.agHelper.ValidateToastMessage(toastToCheck); + } //Assert no error toast in Edit mode when navigating back from Deploy mode this.agHelper.AssertElementAbsence( this.locator._specificToast("There was an unexpected error"), @@ -166,11 +161,23 @@ export class DeployMode { "Internal server error while processing request", ), ); - cy.window().then((win) => { - win.location.reload(); - }); //only reloading edit page to load elements - this.assertHelper.AssertDocumentReady(); + this.agHelper.AssertElementAbsence( + this.locator._specificToast("Cannot read properties of undefined"), + ); + this.assertHelper.AssertNetworkResponseData("@getPluginForm"); //for auth rest api + this.assertHelper.AssertNetworkResponseData("@getPluginForm"); //for graphql this.assertHelper.AssertNetworkStatus("@getWorkspace"); + + // cy.window().then((win) => { + // win.location.reload(); + // }); + // cy.url().then((url) => {//also not working consistently! + // cy.window().then((window) => { + // window.location.href = url; + // }); // //only reloading edit page to load elements + // }); + this.assertHelper.AssertDocumentReady(); + //this.agHelper.Sleep(2000); this.agHelper.AssertElementVisibility(this.locator._editPage); //Assert if canvas is visible after Navigating back! } diff --git a/app/client/cypress/support/Pages/EntityExplorer.ts b/app/client/cypress/support/Pages/EntityExplorer.ts index a56ca3ee11..9bbdb6101c 100644 --- a/app/client/cypress/support/Pages/EntityExplorer.ts +++ b/app/client/cypress/support/Pages/EntityExplorer.ts @@ -2,12 +2,8 @@ import { ObjectsRegistry } from "../Objects/Registry"; import { EntityItems } from "./AssertHelper"; type templateActions = - | "SELECT" - | "INSERT" - | "UPDATE" - | "DELETE" | "Find" - | "Find by ID" + | "Find by id" | "Insert" | "Update" | "Delete" @@ -32,6 +28,7 @@ interface EntityActionParams { | "Refresh" | "Set as home page"; subAction?: string; + //@ts-expect-error: type mismatch entityType?: EntityItems; toAssertAction?: boolean; toastToValidate?: string; @@ -48,7 +45,7 @@ export class EntityExplorer { entityNameinLeftSidebar + "']/ancestor::div[1]/following-sibling::div//button[contains(@class, 'entity-context-menu')]"; _entityNameInExplorer = (entityNameinLeftSidebar: string) => - "//div[contains(@class, 't--entity-name')][text()='" + + "//div[contains(@class, 't--entity-explorer')]//div[contains(@class, 't--entity-name')][text()='" + entityNameinLeftSidebar + "']"; private _expandCollapseArrow = (entityNameinLeftSidebar: string) => @@ -151,11 +148,17 @@ export class EntityExplorer { index = 0, force = false, ) { - this.agHelper.GetNClick( - this._openNavigationTab(navigationTab), - index, - force, - ); + this.agHelper + .GetAttribute(this._openNavigationTab(navigationTab), "data-selected") + .then(($value) => { + if ($value === "true") return; + else + this.agHelper.GetNClick( + this._openNavigationTab(navigationTab), + index, + force, + ); + }); } public AssertEntityPresenceInExplorer(entityNameinLeftSidebar: string) { @@ -236,10 +239,10 @@ export class EntityExplorer { } public ActionContextMenuByEntityName({ - entityNameinLeftSidebar, action = "Delete", - subAction = "", + entityNameinLeftSidebar, entityType = EntityItems.Query, + subAction = "", toAssertAction, toastToValidate = "", }: EntityActionParams) { @@ -309,14 +312,8 @@ export class EntityExplorer { this.agHelper.Sleep(500); } - public DragNDropWidget( - widgetType: string, - x = 300, - y = 100, - parentWidgetType = "", - dropTargetId = "", - ) { - this.NavigateToSwitcher("Widgets"); + public SearchWidgetPane(widgetType: string) { + this.NavigateToSwitcher("Widgets", 0, true); this.agHelper.Sleep(); this.agHelper.ClearTextField(this.locator._entityExplorersearch); this.agHelper.TypeText( @@ -324,6 +321,20 @@ export class EntityExplorer { widgetType.split("widget")[0].trim(), ); this.agHelper.Sleep(500); + } + + public DragNDropWidget( + widgetType: string, + x = 300, + y = 100, + parentWidgetType = "", + dropTargetId = "", + skipWidgetSearch = false, + ) { + if (!skipWidgetSearch) { + this.SearchWidgetPane(widgetType); + } + cy.get(this.locator._widgetPageIcon(widgetType)) .first() .trigger("dragstart", { force: true }) @@ -358,8 +369,16 @@ export class EntityExplorer { y = 100, parentWidgetType = "", dropTargetId = "", + skipWidgetSearch = false, ) { - this.DragNDropWidget(widgetType, x, y, parentWidgetType, dropTargetId); + this.DragNDropWidget( + widgetType, + x, + y, + parentWidgetType, + dropTargetId, + skipWidgetSearch, + ); this.agHelper.AssertAutoSave(); //settling time for widget on canvas! if (widgetType === "modalwidget") { cy.get(".t--modal-widget").should("exist"); @@ -436,9 +455,11 @@ export class EntityExplorer { action: "Edit name", }); else cy.xpath(this._entityNameInExplorer(entityName)).dblclick(); - cy.xpath(this.locator._entityNameEditing(entityName)).type( - renameVal + "{enter}", - ); + cy.xpath(this.locator._entityNameEditing(entityName)) + .type(renameVal) + .wait(500) + .type("{enter}") + .wait(300); this.AssertEntityPresenceInExplorer(renameVal); this.agHelper.Sleep(); //allowing time for name change to reflect in EntityExplorer } diff --git a/app/client/cypress/support/Pages/GitSync.ts b/app/client/cypress/support/Pages/GitSync.ts index d78b7b2247..40dd9f1a76 100644 --- a/app/client/cypress/support/Pages/GitSync.ts +++ b/app/client/cypress/support/Pages/GitSync.ts @@ -44,6 +44,16 @@ export class GitSync { public _discardCallout = "[data-testid='t--discard-callout']"; public _gitStatusChanges = "[data-testid='t--git-change-statuses']"; private _gitSyncBranches = ".t--sync-branches"; + learnMoreSshUrl = ".t--learn-more-ssh-url"; + repoLimitExceededErrorModal = ".t--git-repo-limited-modal"; + public _bottomSettingsBtn = ".t--bottom-git-settings"; + public _defaultBranchSelect = "[data-testid='t--git-default-branch-select']"; + public _defaultBranchUpdateBtn = + "[data-testid='t--git-default-branch-update-btn']"; + public _protectedBranchesSelect = + "[data-testid='t--git-protected-branches-select']"; + public _protectedBranchesUpdateBtn = + "[data-testid='t--git-protected-branches-update-btn']"; OpenGitSyncModal() { this.agHelper.GetNClick(this._connectGitBottomBar); @@ -118,7 +128,8 @@ export class GitSync { this.agHelper.ClickButton("Generate key"); this.agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { - cy.wait(`@generateKey-${repo}`).then((result: any) => { + this.assertHelper.AssertNetworkStatus("@generateKey-" + repo, [200, 201]); + cy.get(`@generateKey-${repo}`).then((result: any) => { generatedKey = result.response.body.data.publicKey; generatedKey = generatedKey.slice(0, generatedKey.length - 1); // fetch the generated key and post to the github repo @@ -154,12 +165,149 @@ export class GitSync { this.assertHelper.AssertNetworkStatus("@connectGitLocalRepo"); this.agHelper.AssertElementExist(this._bottomBarCommit, 0, 30000); this.CloseGitSyncModal(); + this.agHelper.Sleep(2000); //for generatedKey to be available in CI runs + this.assertHelper.AssertNetworkStatus("@generatedKey", 201); } else { + this.assertHelper.AssertContains( + "Error while accessing the file system", + "not.exist", + ); this.assertHelper.AssertNetworkStatus("@importFromGit", 201); } } } + private providerRadioOthers = "[data-testid='t--git-provider-radio-others']"; + private existingEmptyRepoYes = "[data-testid='t--existing-empty-repo-yes']"; + private gitConnectNextBtn = "[data-testid='t--git-connect-next-button']"; + private remoteUrlInput = "[data-testid='git-connect-remote-url-input']"; + private addedDeployKeyCheckbox = + "[data-testid='t--added-deploy-key-checkbox']"; + private startUsingGitButton = "[data-testid='t--start-using-git-button']"; + private existingRepoCheckbox = "[data-testid='t--existing-repo-checkbox']"; + + CreateNConnectToGitV2( + repoName = "Repo", + assertConnect = true, + privateFlag = false, + ) { + this.agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + repoName += uid; + this.CreateTestGiteaRepo(repoName, privateFlag); + + cy.intercept("POST", "/api/v1/applications/ssh-keypair/*").as( + `generateKey-${repoName}`, + ); + + this.OpenGitSyncModal(); + + this.agHelper.GetNClick(this.providerRadioOthers); + this.agHelper.GetNClick(this.existingEmptyRepoYes); + this.agHelper.GetNClick(this.gitConnectNextBtn); + this.agHelper.AssertAttribute( + this.remoteUrlInput, + "placeholder", + "git@example.com:user/repository.git", + ); + this.agHelper.TypeText( + this.remoteUrlInput, + `${this.dataManager.GITEA_API_URL_TED}/${repoName}.git`, + ); + this.agHelper.GetNClick(this.gitConnectNextBtn); + + this.agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + cy.wait(`@generateKey-${repoName}`).then((result: any) => { + let generatedKey = result.response.body.data.publicKey; + generatedKey = generatedKey.slice(0, generatedKey.length - 1); + // fetch the generated key and post to the github repo + cy.request({ + method: "POST", + url: `${this.dataManager.GITEA_API_BASE_TED}:${this.dataManager.GITEA_API_PORT_TED}/api/v1/repos/Cypress/${repoName}/keys`, + headers: { + Authorization: `token ${Cypress.env("GITEA_TOKEN")}`, + }, + body: { + title: "key_" + uid, + key: generatedKey, + read_only: false, + }, + }).then((resp: any) => { + cy.log("Deploy Key Id ", resp.body.key_id); + cy.wrap(resp.body.key_id).as("deployKeyId"); + }); + }); + }); + this.agHelper.GetNClick(this.addedDeployKeyCheckbox, 0, true); + this.agHelper.GetNClick(this.gitConnectNextBtn); + + if (assertConnect) { + this.assertHelper.AssertNetworkStatus("@connectGitLocalRepo"); + this.agHelper.GetNClick(this.startUsingGitButton); + this.agHelper.AssertElementExist(this._bottomBarCommit, 0, 30000); + } + + cy.wrap(repoName).as("gitRepoName"); + }); + } + + public ImportAppFromGitV2( + workspaceName: string, + repoName: string, + assertConnect = true, + ) { + cy.intercept("GET", "api/v1/git/import/keys?keyType=ECDSA").as( + `importKey-${repoName}`, + ); + + this.homePage.ImportGitApp(workspaceName); + + this.agHelper.GetNClick(this.providerRadioOthers); + this.agHelper.GetNClick(this.existingRepoCheckbox, 0, true); + this.agHelper.GetNClick(this.gitConnectNextBtn); + this.agHelper.AssertAttribute( + this.remoteUrlInput, + "placeholder", + "git@example.com:user/repository.git", + ); + this.agHelper.TypeText( + this.remoteUrlInput, + `${this.dataManager.GITEA_API_URL_TED}/${repoName}.git`, + ); + this.agHelper.GetNClick(this.gitConnectNextBtn); + + this.agHelper.GenerateUUID(); + cy.get("@guid").then((uid) => { + cy.wait(`@importKey-${repoName}`).then((result: any) => { + let generatedKey = result.response.body.data.publicKey; + generatedKey = generatedKey.slice(0, generatedKey.length - 1); + // fetch the generated key and post to the github repo + cy.request({ + method: "POST", + url: `${this.dataManager.GITEA_API_BASE_TED}:${this.dataManager.GITEA_API_PORT_TED}/api/v1/repos/Cypress/${repoName}/keys`, + headers: { + Authorization: `token ${Cypress.env("GITEA_TOKEN")}`, + }, + body: { + title: "key_" + uid, + key: generatedKey, + read_only: false, + }, + }).then((resp: any) => { + cy.log("Deploy Key Id ", resp.body.key_id); + cy.wrap(resp.body.key_id).as("deployKeyId"); + }); + }); + }); + this.agHelper.GetNClick(this.addedDeployKeyCheckbox, 0, true); + this.agHelper.GetNClick(this.gitConnectNextBtn); + + if (assertConnect) { + this.assertHelper.AssertNetworkStatus("@importFromGit", 201); + } + } + public ImportAppFromGit( workspaceName: string, repo: string, @@ -202,7 +350,11 @@ export class GitSync { }); } - CreateGitBranch(branch = "br", toUseNewGuid = false) { + CreateGitBranch( + branch = "br", + toUseNewGuid = false, + assertCreateBranch = true, + ) { if (toUseNewGuid) this.agHelper.GenerateUUID(); this.agHelper.AssertElementExist(this._bottomBarCommit); this.agHelper.GetNClick(this._branchButton); @@ -214,6 +366,13 @@ export class GitSync { `{selectall}` + `${branch + uid}` + `{enter}`, { parseSpecialCharSeq: true }, ); + assertCreateBranch && + this.assertHelper.AssertNetworkStatus("createBranch", 201); + this.agHelper.AssertElementAbsence( + this.locator._specificToast( + "Unable to import application in workspace", + ), + ); this.agHelper.AssertElementExist(this.locator._btnSpinner); this.agHelper.AssertElementAbsence(this.locator._btnSpinner, 70000); //Since page taking more time to laod in some cases this.agHelper.AssertElementVisibility(this._branchName(branch + uid)); @@ -241,7 +400,7 @@ export class GitSync { method: "GET", url: "/api/v1/git/checkout-branch/app/**", }, - (req) => { + async (req) => { return new Promise((resolve) => { setTimeout(() => resolve(req.continue()), 1000); }); @@ -282,13 +441,13 @@ export class GitSync { this.agHelper.GetNClick(this._openRepoButton); } - CommitAndPush(assertFailure?: true) { + CommitAndPush(assertSuccess = true) { this.agHelper.GetNClick(this.locator._publishButton); this.agHelper.AssertElementExist(this._bottomBarPull); //cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); this.agHelper.TypeText(this._commitCommentInput, "Initial commit"); this.agHelper.GetNClick(this._commitButton); - if (!assertFailure) { + if (assertSuccess) { // check for commit success //adding timeout since commit is taking longer sometimes this.assertHelper.AssertNetworkStatus("@commit", 201); diff --git a/app/client/cypress/support/Pages/HomePage.ts b/app/client/cypress/support/Pages/HomePage.ts index b1af188231..5a216d42ac 100644 --- a/app/client/cypress/support/Pages/HomePage.ts +++ b/app/client/cypress/support/Pages/HomePage.ts @@ -1,6 +1,7 @@ import { ObjectsRegistry } from "../Objects/Registry"; import { REPO, CURRENT_REPO } from "../../fixtures/REPO"; import HomePageLocators from "../../locators/HomePage"; +import SignupPageLocators from "../../locators/SignupPage.json"; export class HomePage { private agHelper = ObjectsRegistry.AggregateHelper; private locator = ObjectsRegistry.CommonLocators; @@ -54,7 +55,7 @@ export class HomePage { private _homeAppsmithImage = "a.t--appsmith-logo"; _appContainer = ".t--applications-container"; _homePageAppCreateBtn = this._appContainer + " .createnew"; - private _existingWorkspaceCreateNewApp = (existingWorkspaceName: string) => + _existingWorkspaceCreateNewApp = (existingWorkspaceName: string) => `//span[text()='${existingWorkspaceName}']/ancestor::div[contains(@class, 't--workspace-section')]//button[contains(@class, 't--new-button')]`; _applicationName = ".t--application-name"; private _editAppName = "bp3-editable-text-editing"; @@ -83,8 +84,7 @@ export class HomePage { private _uploadFile = "//div/form/input"; private _importSuccessModal = ".t--import-app-success-modal"; private _forkModal = ".fork-modal"; - private _importSuccessModalGotit = ".t--import-success-modal-got-it"; - private _appCard = (applicationName: string) => + public _appCard = (applicationName: string) => "//span[text()='" + applicationName + "']/ancestor::div[contains(@class, 't--application-card')]"; @@ -115,31 +115,51 @@ export class HomePage { _modeSwitchToggle = ".t--comment-mode-switch-toggle"; _importFromGitBtn = "div.t--import-json-card + div"; private signupUsername = "input[name='email']"; - private roleDropdown = ".setup-dropdown:first"; - private useCaseDropdown = ".setup-dropdown:last"; - private dropdownOption = ".rc-select-item-option:first"; - private roleUsecaseSubmit = ".t--get-started-button"; + _multipleSelectedApplication = ".t--application-card-selected"; + private _applicationEditedText = (applicationName: string) => + this._appCard(applicationName) + + "//div[contains(@class, 't--application-edited-text')]"; public SwitchToAppsTab() { this.agHelper.GetNClick(this._homeTab); } - public CreateNewWorkspace( - workspaceNewName: string, - toNavigateToHome = false, - ) { + //trying to wrap multiple values, not used + public WrapAndAliasMultipleValues( + values: Record, + ): Record { + const aliases: Record = {}; + Object.keys(values).forEach((key) => { + aliases[key] = values[key]; + cy.wrap(values[key]).as(key); + }); + return aliases; + } + + public CreateNewWorkspace(workspaceNewName = "", toNavigateToHome = false) { if (toNavigateToHome) this.NavigateToHome(); let oldName = ""; this.agHelper.GetNClick(this._newWorkSpaceLink); this.assertHelper.AssertNetworkStatus("createWorkspace", 201); this.agHelper.Sleep(2000); - cy.xpath(this._lastWorkspaceInHomePage) - .first() - .then(($ele) => { - oldName = $ele.text(); - cy.log("oldName is : " + oldName); - this.RenameWorkspace(oldName, workspaceNewName); - }); + cy.get("@createWorkspace").then((interception: any) => { + localStorage.setItem("workspaceId", interception.response.body.data.id); + localStorage.setItem( + "workspaceName", + interception.response.body.data.name, + ); + cy.wrap(interception.response.body.data.name).as("workspaceName"); + }); + + workspaceNewName && + cy + .xpath(this._lastWorkspaceInHomePage) + .first() + .then(($ele) => { + oldName = $ele.text(); + cy.log("oldName is : " + oldName); + this.RenameWorkspace(oldName, workspaceNewName); + }); } public OpenWorkspaceOptions(workspaceName: string) { @@ -165,6 +185,7 @@ export class HomePage { this.agHelper.Sleep(2000); this.assertHelper.AssertNetworkStatus("@updateWorkspace"); this.agHelper.AssertContains(newWorkspaceName); + this.agHelper.Sleep(2000); //for new workspace to settle for CI } //Maps to CheckShareIcon in command.js @@ -233,8 +254,8 @@ export class HomePage { } public NavigateToHome() { - cy.get(this._homeIcon).click({ force: true }); - this.agHelper.Sleep(2000); + this.agHelper.Sleep(2000); //to avoid CI flakyness + this.agHelper.GetNClick(this._homeIcon, 0, true, 2500); if (!Cypress.env("AIRGAPPED")) { this.assertHelper.AssertNetworkStatus("@getReleaseItems"); } else { @@ -244,29 +265,40 @@ export class HomePage { this.agHelper.AssertElementVisibility(this._homeAppsmithImage); } - public CreateNewApplication() { - cy.get(this._homePageAppCreateBtn).first().click({ force: true }); + public AssertApplicationCreated() { this.assertHelper.AssertNetworkStatus("@createNewApplication", 201); - cy.get(this.locator._loading).should("not.exist"); + cy.get("@createNewApplication").then((interception: any) => { + localStorage.setItem("applicationId", interception.response.body.data.id); + localStorage.setItem("appName", interception.response.body.data.name); + cy.wrap(interception.response.body.data.name).as("appName"); + cy.wrap(interception.response.body.data.id).as("applicationId"); + }); + this.agHelper.AssertElementAbsence(this.locator._loading); + } + public CreateNewApplication(skipSignposting = true) { + cy.get(this._homePageAppCreateBtn).first().click({ force: true }); + this.AssertApplicationCreated(); if (skipSignposting) { this.agHelper.AssertElementVisibility( this.entityExplorer._entityExplorer, ); - this.onboarding.closeIntroModal(); + this.onboarding.skipSignposting(); } + this.agHelper.Sleep(2000); //for getWorkspace to go thru! this.assertHelper.AssertNetworkStatus("getWorkspace"); } //Maps to CreateAppForWorkspace in command.js public CreateAppInWorkspace(workspaceName: string, appname = "") { - cy.xpath(this._existingWorkspaceCreateNewApp(workspaceName)) + this.agHelper + .GetElement(this._existingWorkspaceCreateNewApp(workspaceName)) .last() .scrollIntoView() .should("be.visible") .click({ force: true }); - this.assertHelper.AssertNetworkStatus("@createNewApplication", 201); - cy.get(this.locator._loading).should("not.exist"); + this.AssertApplicationCreated(); + this.agHelper.AssertElementAbsence(this.locator._loading); this.agHelper.Sleep(2000); if (appname) this.RenameApplication(appname); //this.assertHelper.AssertNetworkStatus("@updateApplication", 200); @@ -285,7 +317,7 @@ export class HomePage { }); cy.get(this._applicationName).type(appName); this.agHelper.PressEnter(); - this.agHelper.RemoveTooltip("Rename application"); + this.agHelper.RemoveUIElement("Tooltip", "Rename application"); } public GetAppName() { @@ -314,13 +346,39 @@ export class HomePage { return this.agHelper.Sleep(); //for logout to complete! } + public GotoProfileMenu() { + this.agHelper.GetNClick(this._profileMenu); + } + + public GotoEditProfile() { + cy.location().then((loc) => { + if (loc.pathname !== "/profile") { + this.NavigateToHome(); + this.GotoProfileMenu(); + this.agHelper.GetNClick(this._editProfileMenu); + } + }); + } + + public InvokeDispatchOnStore() { + cy.window().then((win: any) => { + if (win && win.store) { + cy.window() + .its("store") + .invoke("dispatch", { type: "LOGOUT_USER_INIT" }); + } else { + // Handle the case where "store" is not present, or simply ignore and continue. + } + }); + } + public LogintoApp( uname: string, pswd: string, role: "App Viewer" | "Developer" | "Administrator" = "Administrator", ) { this.agHelper.Sleep(); //waiting for window to load - cy.window().its("store").invoke("dispatch", { type: "LOGOUT_USER_INIT" }); + this.InvokeDispatchOnStore(); cy.wait("@postLogout"); this.agHelper.VisitNAssert("/user/login", "signUpLogin"); this.agHelper.AssertElementVisibility(this._username); @@ -340,9 +398,6 @@ export class HomePage { } public SignUp(uname: string, pswd: string) { - this.agHelper.Sleep(); //waiting for window to load - cy.window().its("store").invoke("dispatch", { type: "LOGOUT_USER_INIT" }); - cy.wait("@postLogout"); this.agHelper.VisitNAssert("/user/signup", "signUpLogin"); this.agHelper.AssertElementVisibility(this.signupUsername); this.agHelper.TypeText(this.signupUsername, uname); @@ -350,12 +405,26 @@ export class HomePage { this.agHelper.GetNClick(this._submitBtn); this.agHelper.Sleep(1000); cy.get("body").then(($body) => { - if ($body.find(this.roleDropdown).length > 0) { - this.agHelper.GetNClick(this.roleDropdown); - this.agHelper.GetNClick(this.dropdownOption); - this.agHelper.GetNClick(this.useCaseDropdown); - this.agHelper.GetNClick(this.dropdownOption); - this.agHelper.GetNClick(this.roleUsecaseSubmit, undefined, true); + if ($body.find(SignupPageLocators.roleDropdown).length > 0) { + this.agHelper.GetNClick(SignupPageLocators.roleDropdown); + this.agHelper.GetNClick(SignupPageLocators.dropdownOption); + this.agHelper.GetNClick(SignupPageLocators.useCaseDropdown); + this.agHelper.GetNClick(SignupPageLocators.dropdownOption); + this.agHelper.GetNClick( + SignupPageLocators.getStartedSubmit, + undefined, + true, + ); + } else if ( + $body.find(SignupPageLocators.proficiencyGroupButton).length > 0 + ) { + this.agHelper.GetNClick(SignupPageLocators.proficiencyGroupButton); + this.agHelper.GetNClick(SignupPageLocators.useCaseGroupButton); + this.agHelper.GetNClick( + SignupPageLocators.getStartedSubmit, + undefined, + true, + ); } }); this.assertHelper.AssertNetworkStatus("@getMe"); @@ -384,7 +453,7 @@ export class HomePage { public SearchAndOpenApp(appName: string) { this.agHelper.TypeText(this._searchInput, appName); this.agHelper.Sleep(2000); - this.EditAppFromAppHover(); + this.EditAppFromAppHover(appName); } //Maps to launchApp in command.js @@ -394,8 +463,17 @@ export class HomePage { this.assertHelper.AssertNetworkStatus("getPagesForViewApp"); } - public EditAppFromAppHover() { - cy.get(this._applicationCard).first().trigger("mouseover"); + public EditAppFromAppHover(appName = "") { + if (appName) + this.agHelper + .GetElement(this._appCard(appName)) + .first() + .trigger("mouseover"); + else + this.agHelper + .GetElement(this._applicationCard) + .first() + .trigger("mouseover"); this.agHelper.GetNClick(this._appHoverIcon("edit")); this.agHelper.AssertElementAbsence(this.locator._loading); this.assertHelper.AssertNetworkStatus("getWorkspace"); @@ -477,17 +555,29 @@ export class HomePage { this.NavigateToHome(); } - public ImportApp(fixtureJson: string, intoWorkspaceName = "") { - cy.get(this._homeIcon).click({ force: true }); - if (intoWorkspaceName) - this.agHelper.GetNClick(this._optionsIconInWorkspace(intoWorkspaceName)); - else this.agHelper.GetNClick(this._optionsIcon); - this.agHelper.GetNClick(this._workspaceImport, 0, true); - this.agHelper.AssertElementVisibility(this._workspaceImportAppModal); + public ImportApp( + fixtureJson: string, + intoWorkspaceName = "", + onlyImport = false, + ) { + this.agHelper.Sleep(3000); //for new workspace to settle for CI + if (onlyImport === false) { + cy.get(this._homeIcon).click({ force: true }); + if (intoWorkspaceName) + this.agHelper.GetNClick( + this._optionsIconInWorkspace(intoWorkspaceName), + ); + else this.agHelper.GetNClick(this._optionsIcon); + this.agHelper.GetNClick(this._workspaceImport, 0, true); + this.agHelper.AssertElementVisibility(this._workspaceImportAppModal); + } cy.xpath(this._uploadFile).selectFile("cypress/fixtures/" + fixtureJson, { force: true, }); this.agHelper.Sleep(3500); + this.agHelper.AssertElementAbsence( + this.locator._specificToast("Unable to import application in workspace"), + ); } public ImportGitApp(intoWorkspaceName = "") { @@ -571,7 +661,7 @@ export class HomePage { this.agHelper.AssertElementVisibility( this.locator._visibleTextSpan("Your application is ready to use."), ); - this.agHelper.GetNClick(this._importSuccessModalGotit, 0, true); + this.agHelper.ClickButton("Got it"); } public AssertImportToast(timeout = 5000) { @@ -601,6 +691,17 @@ export class HomePage { this.agHelper.WaitUntilToastDisappear("Deleting application..."); } + public DeleteAppviaAPI(appId: any) { + cy.request({ + method: "DELETE", + url: "api/v1/applications/" + appId, + failOnStatusCode: false, + headers: { + "X-Requested-By": "Appsmith", + }, + }); + } + //Maps to leaveworkspace in command.js public LeaveWorkspace(workspaceName: string) { this.OpenWorkspaceOptions(workspaceName); @@ -621,4 +722,15 @@ export class HomePage { } }); } + + public SelectMultipleApplicationToDelete(applicationName: string) { + this.agHelper.GetNClick( + this._applicationEditedText(applicationName), + 0, + false, + 500, + false, + true, + ); + } } diff --git a/app/client/cypress/support/Pages/InviteModal.ts b/app/client/cypress/support/Pages/InviteModal.ts index f5f6acdc54..86ffa1fbc6 100644 --- a/app/client/cypress/support/Pages/InviteModal.ts +++ b/app/client/cypress/support/Pages/InviteModal.ts @@ -7,10 +7,12 @@ export class InviteModal { private embedSettings = ObjectsRegistry.EmbedSettings; private deployMode = ObjectsRegistry.DeployMode; private commonLocators = ObjectsRegistry.CommonLocators; + private assertHelper = ObjectsRegistry.AssertHelper; public locators = { _inviteTab: "[data-testid='t--tab-INVITE']", _embedTab: "[data-testid='t--tab-EMBED']", + _publishTab: "[data-testid='t--tab-PUBLISH']", _shareButton: ".t--application-share-btn", _closeButton: ".ads-v2-modal__content-header-close-button", _previewEmbed: "[data-testid='preview-embed']", @@ -84,7 +86,11 @@ export class InviteModal { toggle, toggle == "On" ? false : true, ); - cy.get(this.locators._previewEmbed).invoke("removeAttr", "target").click(); + cy.get(this.locators._previewEmbed) + .invoke("removeAttr", "target") + .click() + .wait(2000); + this.assertHelper.AssertDocumentReady(); this.agHelper.Sleep(3000); //for page to load if (toggle == "On") { this.deployMode.NavigateBacktoEditor(); //Also verifies that navigation bar is present diff --git a/app/client/cypress/support/Pages/JSEditor.ts b/app/client/cypress/support/Pages/JSEditor.ts index 52596b1c70..76ef2988f7 100644 --- a/app/client/cypress/support/Pages/JSEditor.ts +++ b/app/client/cypress/support/Pages/JSEditor.ts @@ -131,12 +131,12 @@ export class JSEditor { cy.get(this.locator._createNew).last().click({ force: true }); cy.get(this._newJSobj).eq(0).click({ force: true }); + this.agHelper.RemoveUIElement("Tooltip", "Add a new query/JS Object"); //Checking JS object was created successfully this.assertHelper.AssertNetworkStatus("@jsCollections", 200); // Assert that the name of the JS Object is focused when newly created //cy.get(this._jsObjTxt).should("be.focused").type("{enter}"); - this.agHelper.PressEnter(); //for name to settle - this.agHelper.Sleep(); + this.agHelper.PressEnter(1000); //for name to settle // Assert that the name of the JS Object is no longer in the editable form after pressing "enter" cy.get(this._jsObjTxt).should("not.exist"); @@ -147,16 +147,16 @@ export class JSEditor { public CreateJSObject( JSCode: string, - options: ICreateJSObjectOptions = DEFAULT_CREATE_JS_OBJECT_OPTIONS, + options: Partial = {}, ) { const { completeReplace, - lineNumber = 4, + lineNumber, paste, - prettify = true, + prettify, shouldCreateNewJSObj, toRun, - } = options; + } = { ...DEFAULT_CREATE_JS_OBJECT_OPTIONS, ...options }; shouldCreateNewJSObj && this.NavigateToNewJSEditor(); if (!completeReplace) { @@ -229,7 +229,7 @@ export class JSEditor { public RunJSObj() { this.agHelper.GetNClick(this._runButton); this.agHelper.Sleep(); //for function to run - this.agHelper.AssertElementAbsence(this.locator._btnSpinner, 10000); + this.agHelper.AssertElementAbsence(this.locator._btnSpinner, 15000); this.agHelper.AssertElementAbsence(this.locator._empty, 5000); } diff --git a/app/client/cypress/support/Pages/LibraryInstaller.ts b/app/client/cypress/support/Pages/LibraryInstaller.ts index 7155c47978..809e213d87 100644 --- a/app/client/cypress/support/Pages/LibraryInstaller.ts +++ b/app/client/cypress/support/Pages/LibraryInstaller.ts @@ -4,7 +4,8 @@ export class LibraryInstaller { private _aggregateHelper = ObjectsRegistry.AggregateHelper; private _installer_trigger_locator = ".t--entity-add-btn.group.libraries button"; - private _installer_close_locator = ".t--close-installer"; + private _installer_close_locator = + ".ads-v2-popover__body-header .ads-v2-icon"; private getLibraryLocatorInExplorer(libraryName: string) { return `.t--installed-library-${libraryName}`; @@ -14,6 +15,9 @@ export class LibraryInstaller { return `div.library-card.t--${libraryName}`; } + private libraryURLLocator = "[data-testid='library-url']"; + private installBtnLocator = "[data-testid='install-library-btn']"; + public OpenInstaller(force = false) { this._aggregateHelper.GetNClick(this._installer_trigger_locator, 0, force); } @@ -22,7 +26,7 @@ export class LibraryInstaller { this._aggregateHelper.GetNClick(this._installer_close_locator); } - public installLibrary( + public InstallLibrary( libraryName: string, accessor: string, checkIfSuccessful = true, @@ -33,6 +37,20 @@ export class LibraryInstaller { if (checkIfSuccessful) this.assertInstall(libraryName, accessor); } + public InstallLibraryViaURL( + url: string, + accessor: string, + checkIfSuccessful = true, + ) { + this._aggregateHelper.TypeText(this.libraryURLLocator, url); + this._aggregateHelper.GetNClick(this.installBtnLocator); + if (checkIfSuccessful) { + this._aggregateHelper.AssertContains( + `Installation Successful. You can access the library via ${accessor}`, + ); + } + } + private assertInstall(libraryName: string, accessor: string) { this._aggregateHelper.AssertContains( `Installation Successful. You can access the library via ${accessor}`, @@ -53,7 +71,7 @@ export class LibraryInstaller { } public assertUnInstall(libraryName: string) { - this._aggregateHelper.AssertContains( + this._aggregateHelper.WaitUntilToastDisappear( `${libraryName} is uninstalled successfully.`, ); this._aggregateHelper.AssertElementAbsence( diff --git a/app/client/cypress/support/Pages/MultipleEnvironments.ts b/app/client/cypress/support/Pages/MultipleEnvironments.ts new file mode 100644 index 0000000000..73e4929974 --- /dev/null +++ b/app/client/cypress/support/Pages/MultipleEnvironments.ts @@ -0,0 +1,69 @@ +import { agHelper, dataSources } from "../Objects/ObjectsCore"; +import { ObjectsRegistry } from "../Objects/Registry"; + +export class MultipleEnvironments { + private agHelper = ObjectsRegistry.AggregateHelper; + private locator = ObjectsRegistry.CommonLocators; + private dataManager = ObjectsRegistry.DataManager; + + public env_switcher = '[data-testid="t--switch-env"]'; + public env_switcher_dropdown_opt_prod = + '[data-testid="t--switch-env-dropdown-option-production"]'; + public env_switcher_dropdown_opt_stage = + '[data-testid="t--switch-env-dropdown-option-staging"]'; + public ds_data_filter_disabled = '[data-testid="t--filter-disabled"]'; + public ds_data_dropdown_tooltip = '[data-testid="t--switch-env-tooltip"]'; + public env_switcher_dropdown_opt = (envName: string) => + `[data-testid="t--switch-env-dropdown-option-${envName}"]`; + public ds_review_mode_configs = (envName: string) => + `[data-testid="t--review-section-${envName}"]`; + + public SwitchEnv(targetEnv: string) { + this.agHelper + .GetElement(this.env_switcher) + .eq(0) + .invoke("text") + .then((text: string) => { + if (text.toLowerCase() === targetEnv.toLowerCase()) { + cy.log("Already in target env"); + } else { + cy.log( + `Currently in ${text + .toString() + .toLowerCase()} Switching to target env: ${targetEnv.toLowerCase()}`, + ); + this.agHelper.GetNClick(this.env_switcher); + this.agHelper.GetNClick(this.env_switcher_dropdown_opt(targetEnv)); + this.agHelper.Sleep(); + this.agHelper.AssertElementExist( + this.locator._specificToast( + `Environment switched to ${targetEnv.toLowerCase()}`, + ), + ); + } + }); + agHelper.Sleep(3000); // adding wait for page to load + } + + public SwitchEnvInDSEditor( + target_environment = this.dataManager.defaultEnviorment, + ) { + this.agHelper.GetNClick( + this.locator.ds_editor_env_filter(target_environment), + ); + this.agHelper.AssertSelectedTab( + this.locator.ds_editor_env_filter(target_environment), + "true", + ); + } + + public VerifyEnvDetailsInReviewMode( + dsName: "PostgreSQL" | "MongoDB", + envName: string, + ) { + this.agHelper.AssertElementExist(this.ds_review_mode_configs(envName)); + dataSources.ValidateReviewModeConfig(dsName, envName); + } + + //#endregion +} diff --git a/app/client/cypress/support/Pages/Onboarding.ts b/app/client/cypress/support/Pages/Onboarding.ts index d37885470e..d0c96a4e54 100644 --- a/app/client/cypress/support/Pages/Onboarding.ts +++ b/app/client/cypress/support/Pages/Onboarding.ts @@ -1,4 +1,5 @@ import { ObjectsRegistry } from "../Objects/Registry"; +import localForage from "localforage"; const OnboardingLocator = require("../../locators/FirstTimeUserOnboarding.json"); @@ -8,6 +9,16 @@ export class Onboarding { private _datasources = ObjectsRegistry.DataSources; private _debuggerHelper = ObjectsRegistry.DebuggerHelper; + public readonly locators = { + back_to_canvas: "#back-to-canvas", + deploy: "#application-publish-btn", + table_widget_card: "#widget-card-draggable-tablewidgetv2", + create_query: "#create-query", + explorer_widget_tab: `#explorer-tab-options [data-value*="widgets"]`, + add_datasources: "#add_datasources", + connect_data_overlay: "#table-overlay-connectdata", + }; + completeSignposting() { cy.get(OnboardingLocator.checklistStatus).should("be.visible"); cy.get(OnboardingLocator.checklistStatus).should("contain", "0 of 5"); @@ -108,4 +119,23 @@ export class Onboarding { } }); } + + skipSignposting() { + cy.get("body").then(($body) => { + if ($body.find(OnboardingLocator.introModalCloseBtn).length) { + cy.wrap(null).then(async () => { + localForage.config({ + name: "Appsmith", + }); + // return a promise to cy.then() that + // is awaited until it resolves + return localForage.setItem("ENABLE_START_SIGNPOSTING", false); + }); + //this._aggregateHelper.RefreshPage();//this is causing CI flakiness, so using below + cy.window().then((win) => { + win.location.reload(); + }); + } + }); + } } diff --git a/app/client/cypress/support/Pages/PropertyPane.ts b/app/client/cypress/support/Pages/PropertyPane.ts index 4f82d0df30..051e2bb211 100644 --- a/app/client/cypress/support/Pages/PropertyPane.ts +++ b/app/client/cypress/support/Pages/PropertyPane.ts @@ -23,11 +23,12 @@ export class PropertyPane { private locator = ObjectsRegistry.CommonLocators; private assertHelper = ObjectsRegistry.AssertHelper; + _propertyPaneSidebar = ".t--property-pane-sidebar"; _jsonFieldEdit = (fieldName: string) => "//input[@placeholder='Field label'][@value='" + fieldName + "']/ancestor::div/following-sibling::div/button[contains(@class, 't--edit-column-btn')]"; - private _goBackToProperty = "button[data-testid='t--property-pane-back-btn']"; + public _goBackToProperty = "button[data-testid='t--property-pane-back-btn']"; private _copyWidget = "[data-testid='t--copy-widget']"; _deleteWidget = "[data-testid='t--delete-widget']"; private _styleTabBtn = (tab: string) => @@ -53,11 +54,11 @@ export class PropertyPane { _mode = (modeName: string) => "//span[contains(text(),'" + modeName + "')]//parent::span"; _propertyToggle = (controlToToggle: string) => - ".t--property-control-" + + "//div[contains(@class,'t--property-control-" + controlToToggle.replace(/ +/g, "").toLowerCase() + - " input[type='checkbox'], label:contains('" + + "')]//input[@type='checkbox'] | //label[text()='" + controlToToggle + - "') input[type='checkbox']"; + "']//input[@type='checkbox']"; _colorPickerV2Popover = ".t--colorpicker-v2-popover"; _colorPickerV2Color = ".t--colorpicker-v2-color"; _colorInput = (option: string) => @@ -84,6 +85,7 @@ export class PropertyPane { _selectorViewButton = ".selector-view .bp3-button-text"; _actionOpenDropdownSelectPage = ".t--open-dropdown-Select-page"; _sameWindowDropdownOption = ".t--open-dropdown-Same-window"; + _windowTargetDropdown = ".t--open-dropdown-Window"; _navigateToType = (type: string) => "div.tab-view span:contains('" + type + "')"; @@ -110,7 +112,7 @@ export class PropertyPane { "')]//input[@class='rc-select-selection-search-input']/parent::span/following-sibling::span | //div[contains(@class, 't--property-control-" + ddName.replace(/ +/g, "").toLowerCase() + "')]//div[@class='selected-item']/div"; - private _createModalButton = ".t--create-modal-btn"; + public _createModalButton = ".t--create-modal-btn"; _pageName = (option: string) => "//a/div[text()='" + option + "']"; private isMac = Cypress.platform === "darwin"; private selectAllJSObjectContentShortcut = `${ @@ -135,7 +137,7 @@ export class PropertyPane { _addOptionProperty = ".t--property-control-options-add"; _optionContent = ".rc-select-item-option-content"; _dropdownOptionSpan = ".t--dropdown-option span"; - private _propertyControlColorPicker = (property: string) => + public _propertyControlColorPicker = (property: string) => `.t--property-control-${property} .bp3-input-group input`; _propertyText = ".bp3-ui-text span"; _paneTitle = ".t--property-pane-title"; @@ -147,12 +149,29 @@ export class PropertyPane { `${this.locator._widgetByName(widgetName)} ${this._propertyText}`; _placeholderName = "[placeholder='Name']"; _placeholderValue = "[placeholder='Value']"; - _sliderMark = ".slider-mark"; _optionsDeleteButton = "[orientation='HORIZONTAL'] .ads-v2-button"; + _colorPickerInput = "[data-testid='t--color-picker-input']"; + _emphasisSelector = (value: string) => `.t--button-group-${value}`; + _checkbox = ".bp3-checkbox"; + _roundCursorPointer = ".rounded-full.cursor-pointer"; + _sliderMark = ".slider-mark"; _styleSize = (size: string) => `.ads-v2-segmented-control-value-${size}`; _themeColor = "//h3[text()='Theme Colors']//..//div[contains(@class, 't--colorpicker-v2-color')]"; _fillColor = ".t--colorpicker-v2-popover .rounded-full"; + _multiSelect = ".rc-select-multiple"; + _currencyChangeDropdownIcon = + ".currency-change-dropdown-trigger .remixicon-icon"; + _countryCodeChangeDropDown = ".t--input-country-code-change .remixicon-icon"; + _searchCountryPlaceHolder = "[placeholder='Search by ISD code or country']"; + _closeModal = "//*[contains(@class,'ads-v2-button t--close')]"; + _zoomLevelInput = ".t--property-control-zoomlevel input"; + _zoomLevelControl = (control: "start" | "end") => + ".t--property-control-zoomlevel .ads-v2-input__input-section-icon-" + + control; + + _dataIcon = (icon: string) => `[data-icon="${icon}"]`; + _iconDropdown = "[data-test-id='virtuoso-scroller']"; public OpenJsonFormFieldSettings(fieldName: string) { this.agHelper.GetNClick(this._jsonFieldEdit(fieldName)); @@ -168,7 +187,7 @@ export class PropertyPane { // } // }); this.OpenJsonFormFieldSettings(fieldName); - this.agHelper.SelectDropdownList("Field Type", newDataType); + this.SelectPropertiesDropDown("Field Type", newDataType); this.agHelper.AssertAutoSave(); this.assertHelper.AssertNetworkStatus("@updateLayout"); } @@ -268,6 +287,7 @@ export class PropertyPane { action: "Action" | "Page" = "Action", index = 0, optionIndex = 0, + force = false, ) { if (action == "Action") this.agHelper.GetNClick(this._selectPropDropdown(endpoint), index); @@ -276,7 +296,11 @@ export class PropertyPane { this.locator._selectPropPageDropdown(endpoint), index, ); - this.agHelper.GetNClick(this._dropDownValue(dropdownOption), optionIndex); + this.agHelper.GetNClick( + this._dropDownValue(dropdownOption), + optionIndex, + force, + ); } public AssertPropertiesDropDownCurrentValue( @@ -586,12 +610,11 @@ export class PropertyPane { .type(newName, { force: true }) .should("have.value", newName) .blur(); - this.agHelper.PressEnter(); + this.agHelper.PressEnter(1000); this.assertHelper.AssertNetworkStatus("@updateWidgetName"); - this.agHelper.Sleep(); } - public CreateModal(modalName: string, property: string) { + public CreateModal(property: string) { this.SelectPlatformFunction(property, "Show modal"); this.agHelper.GetNClick(this._actionOpenDropdownSelectModal); this.agHelper.GetNClick(this._createModalButton); @@ -613,4 +636,28 @@ export class PropertyPane { this.agHelper.GetNClick(this._propertyControlColorPicker(property)); this.agHelper.GetNClick(this._colorPickerV2Color, colorOffset, true); } + + public AssertPropertyVisibility(properties: string[], sectionTitle: string) { + properties.forEach((property: string) => { + this.agHelper.AssertElementVisibility( + this._propertyPanePropertyControl(sectionTitle, property), + ); + }); + } + + public SetZoomLevel(zoom: number) { + this.agHelper.GetAttribute(this._zoomLevelInput, "value").then((value) => { + const currentValue = Number(value?.replace("%", "")); + + if (currentValue === zoom || currentValue === 100 || currentValue === 0) { + return; + } + if (zoom > currentValue) { + this.agHelper.GetElement(this._zoomLevelControl("end")).click(); + } else if (zoom < currentValue) { + this.agHelper.GetElement(this._zoomLevelControl("start")).click(); + } + this.SetZoomLevel(zoom); + }); + } } diff --git a/app/client/cypress/support/Pages/Table.ts b/app/client/cypress/support/Pages/Table.ts index 24a33d69b8..14adc90595 100644 --- a/app/client/cypress/support/Pages/Table.ts +++ b/app/client/cypress/support/Pages/Table.ts @@ -89,7 +89,7 @@ export class Table { _liCurrentSelectedPage = "//div[@type='LIST_WIDGET']//ul[contains(@class, 'rc-pagination')]/li[contains(@class, 'rc-pagination-item-active')]/a"; private _tr = ".tbody .tr"; - private _searchText = "input[type='search']"; + private _searchTableInput = "input[type='search'][placeholder='Search...']"; _searchBoxCross = "//div[contains(@class, 't--search-input')]/following-sibling::div"; _addIcon = "button .bp3-icon-add"; @@ -188,13 +188,17 @@ export class Table { _divFirstChild = "div:first-child abbr"; _listPreviousPage = ".rc-pagination-prev"; _listNavigation = (move: string) => - "//button[@area-label='" + move + " page']"; + "//button[@aria-label='" + move + " page']"; _listNextPage = ".rc-pagination-next"; _listActivePage = (version: "v1" | "v2") => `.t--widget-listwidget${ version == "v1" ? "" : version } .rc-pagination-item-active`; _paginationItem = (value: number) => `.rc-pagination-item-${value}`; + _cellWrapOff = "//div[@class='tableWrap virtual']"; + _cellWrapOn = "//div[@class='tableWrap']"; + _multirowselect = ".t--table-multiselect"; + _selectedrow = ".selected-row"; public GetNumberOfRows() { return this.agHelper.GetElement(this._tr).its("length"); @@ -247,15 +251,12 @@ export class Table { } public WaitForTableEmpty(tableVersion: "v1" | "v2" = "v1") { - cy.waitUntil(() => cy.get(this._tableEmptyColumnData(tableVersion)), { - errorMsg: "Table is populated when not expected", - timeout: 10000, - interval: 2000, - }).then(($children) => { - cy.wrap($children).children().should("have.length", 0); //or below - //expect($children).to.have.lengthOf(0) - this.agHelper.Sleep(500); - }); + this.agHelper + .GetElement(this._tableEmptyColumnData(tableVersion)) + .children() + .should("have.length", 0); //or below + //expect($children).to.have.lengthOf(0) + this.agHelper.Sleep(500); } public AssertTableHeaderOrder(expectedOrder: string) { @@ -445,11 +446,11 @@ export class Table { } public AssertSearchText(searchTxt: string, index = 0) { - cy.get(this._searchText).eq(index).should("have.value", searchTxt); + cy.get(this._searchTableInput).eq(index).should("have.value", searchTxt); } public SearchTable(searchTxt: string, index = 0) { - cy.get(this._searchText).eq(index).type(searchTxt); + this.agHelper.TypeText(this._searchTableInput, searchTxt, index); } public ResetSearch() { @@ -552,7 +553,7 @@ export class Table { tableVersion: "v1" | "v2" = "v1", ) { this.EditColumn(columnName, tableVersion); - this.agHelper.SelectDropdownList("Column type", newDataType); + this.propPane.SelectPropertiesDropDown("Column type", newDataType); this.assertHelper.AssertNetworkStatus("@updateLayout"); if (tableVersion == "v2") this.propPane.NavigateBackToPropertyPane(); } diff --git a/app/client/cypress/support/Pages/Tabs.ts b/app/client/cypress/support/Pages/Tabs.ts index 6bbce340a7..913431d182 100644 --- a/app/client/cypress/support/Pages/Tabs.ts +++ b/app/client/cypress/support/Pages/Tabs.ts @@ -8,6 +8,10 @@ export class Tabs { private _tabsWidgetNameSelector = (widgetName: string): string => `.t--widget-${widgetName?.toLowerCase()}`; private _showTabsProperty = "showtabs"; + public _addTab = ".t--add-tab-btn"; + public _placeholderTabTitle = "[placeholder='Tab title']"; + public _tabsWidgetStyle = + "(//div[contains(@class,'t--draggable-tabswidget')]//div)[6]"; public toggleShowTabHeader(showTabs = true, selector: string) { this.agHelper.GetNClick(selector).then(() => { diff --git a/app/client/cypress/support/Pages/Templates.ts b/app/client/cypress/support/Pages/Templates.ts index ff44208ff2..aa5b958063 100644 --- a/app/client/cypress/support/Pages/Templates.ts +++ b/app/client/cypress/support/Pages/Templates.ts @@ -17,10 +17,11 @@ export class Templates { }; FilterTemplatesByName(query: string) { - return ObjectsRegistry.AggregateHelper.TypeText( + ObjectsRegistry.AggregateHelper.TypeText( this.locators._templatesSearchInput, query, ); + this.agHelper.Sleep(); } AssertResultsHeaderText( diff --git a/app/client/cypress/support/WorkspaceCommands.js b/app/client/cypress/support/WorkspaceCommands.js index 2c36fa32b1..1c138a9789 100644 --- a/app/client/cypress/support/WorkspaceCommands.js +++ b/app/client/cypress/support/WorkspaceCommands.js @@ -10,6 +10,7 @@ import { ObjectsRegistry } from "../support/Objects/Registry"; const agHelper = ObjectsRegistry.AggregateHelper; const assertHelper = ObjectsRegistry.AssertHelper; +const homePageTS = ObjectsRegistry.HomePage; export const initLocalstorage = () => { cy.window().then((window) => { @@ -214,6 +215,7 @@ Cypress.Commands.add("launchApp", () => { }); Cypress.Commands.add("AppSetupForRename", () => { + cy.wait(2000); //wait a bit for app to load cy.get(homePage.applicationName).then(($appName) => { if (!$appName.hasClass(homePage.editingAppName)) { cy.get(homePage.applicationName).click({ force: true }); @@ -252,45 +254,58 @@ Cypress.Commands.add("CreateAppForWorkspace", (workspaceName, appname) => { "response.body.responseMeta.status", 200, ); - agHelper.RemoveTooltip("Rename application"); + agHelper.RemoveUIElement("Tooltip", "Rename application"); }); -Cypress.Commands.add("CreateAppInFirstListedWorkspace", (appname) => { - let applicationId; - cy.get(homePage.createNew).first().click({ force: true }); - cy.wait("@createNewApplication").then((xhr) => { +Cypress.Commands.add("CreateNewAppInNewWorkspace", () => { + let applicationId, appName; + let toNavigateToHome = false; + cy.get("body").then(($ele) => { + if ($ele.find(".t--appsmith-logo").length < 0) { + toNavigateToHome = false; + } else { + toNavigateToHome = true; + } + }); + homePageTS.CreateNewWorkspace("", toNavigateToHome); //Creating a new workspace for every test, since we are deleting the workspace in the end of the test + //agHelper.Sleep(2000); //for workspace to open + cy.get("@workspaceName").then((workspaceName) => { + localStorage.setItem("workspaceName", workspaceName); + homePageTS.CreateAppInWorkspace(localStorage.getItem("workspaceName")); + }); + cy.get("@createNewApplication").then((xhr) => { const response = xhr.response; expect(response.body.responseMeta.status).to.eq(201); applicationId = response.body.data.id; + appName = response.body.data.name; + cy.log("appName", appName); localStorage.setItem("applicationId", applicationId); + localStorage.setItem("appName", appName); + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(4000); + cy.get("#loading").should("not.exist"); + + cy.url().then((url) => { + if (url.indexOf("/applications") > -1) { + homePageTS.EditAppFromAppHover(appName); + agHelper.Sleep(2000); //for app to open + } + }); }); - //cy.get("#loading").should("not.exist"); - // eslint-disable-next-line cypress/no-unnecessary-waiting - //cy.reload(); - cy.wait(4000); - cy.get("#loading").should("not.exist"); - - assertHelper.AssertNetworkStatus("@getPage"); - assertHelper.AssertNetworkStatus("@getLibraries"); - assertHelper.AssertNetworkStatus("@getPlugins"); - cy.get("#sidebar").should("be.visible"); - cy.wait("@getPluginForm") //replacing this since flaky in CI - to monitor - .its("response.body.responseMeta.status") - .should("eq", 200); + assertHelper.AssertNetworkResponseData("@getPluginForm"); //for auth rest api + assertHelper.AssertNetworkResponseData("@getPluginForm"); //for graphql - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(2000); + // If the intro modal is open, close it + cy.skipSignposting(); - cy.AppSetupForRename(); - cy.get(homePage.applicationName).type(appname + "{enter}"); - cy.wait("@updateApplication").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); - // Remove tooltip on the Application Name - agHelper.RemoveTooltip("Rename application"); + //Removing renaming of app from all tests, since its also verified in other separate tests + // cy.AppSetupForRename(); + // cy.get(homePage.applicationName).type(appname + "{enter}"); + // assertHelper.AssertNetworkStatus("@updateApplication"); + // // Remove tooltip on the Application Name + // agHelper.RemoveTooltip("Tooltip","Rename application"); /* The server created app always has an old dsl so the layout will migrate * To avoid race conditions between that update layout and this one diff --git a/app/client/cypress/support/commands.js b/app/client/cypress/support/commands.js index 62f14c790c..a7eb2252a1 100644 --- a/app/client/cypress/support/commands.js +++ b/app/client/cypress/support/commands.js @@ -41,6 +41,7 @@ const apiPage = ObjectsRegistry.ApiPage; const deployMode = ObjectsRegistry.DeployMode; const entityExplorer = ObjectsRegistry.EntityExplorer; const assertHelper = ObjectsRegistry.AssertHelper; +const homePageTS = ObjectsRegistry.HomePage; let pageidcopy = " "; const chainStart = Symbol(); @@ -52,6 +53,44 @@ export const initLocalstorage = () => { }); }; +export const addIndexedDBKey = (key, value) => { + cy.window().then((window) => { + // Opening the database + const request = window.indexedDB.open("Appsmith", 2); + + // Handling database opening success + request.onsuccess = (event) => { + const db = event.target.result; + + // Creating a transaction to access the object store : keyvaluepairs + const transaction = db.transaction(["keyvaluepairs"], "readwrite"); + const objectStore = transaction.objectStore("keyvaluepairs"); + + // Adding the key + const addRequest = objectStore.put(value, key); + + // Handling add success + addRequest.onsuccess = () => { + console.log("Key added successfully"); + // Closing the database connection + db.close(); + }; + + // Handling add error + addRequest.onerror = (event) => { + console.log("Error adding key:", event.target.error); + // Closing the database connection + db.close(); + }; + }; + + // Handling database opening error + request.onerror = (event) => { + console.log("Error opening database:", event.target.error); + }; + }); +}; + // Cypress.Commands.add("goToEditFromPublish", () => { // cy.url().then((url) => { // const urlObject = new URL(url); @@ -224,7 +263,7 @@ Cypress.Commands.add("GetUrlQueryParams", () => { Cypress.Commands.add("LogOutUser", () => { cy.wait(1000); //waiting for window to load - cy.window().its("store").invoke("dispatch", { type: "LOGOUT_USER_INIT" }); + homePageTS.InvokeDispatchOnStore(); assertHelper.AssertNetworkStatus("@postLogout", 200); }); @@ -259,7 +298,7 @@ Cypress.Commands.add("LogintoAppTestUser", (uname, pword) => { }); Cypress.Commands.add("Signup", (uname, pword) => { - cy.window().its("store").invoke("dispatch", { type: "LOGOUT_USER_INIT" }); + homePageTS.InvokeDispatchOnStore(); cy.wait("@postLogout"); cy.visit("/user/signup", { timeout: 60000 }); @@ -278,7 +317,11 @@ Cypress.Commands.add("Signup", (uname, pword) => { cy.get(signupPage.dropdownOption).click(); cy.get(signupPage.useCaseDropdown).click(); cy.get(signupPage.dropdownOption).click(); - cy.get(signupPage.roleUsecaseSubmit).click({ force: true }); + cy.get(signupPage.getStartedSubmit).click({ force: true }); + } else if ($body.find(signupPage.proficiencyGroupButton).length > 0) { + cy.get(signupPage.proficiencyGroupButton).first().click(); + cy.get(signupPage.useCaseGroupButton).first().click(); + cy.get(signupPage.getStartedSubmit).click({ force: true }); } }); cy.wait("@getMe"); @@ -310,7 +353,7 @@ Cypress.Commands.add("LoginFromAPI", (uname, pword) => { // Check if cookie is present cy.getCookie("SESSION").then((cookie) => { expect(cookie).to.not.be.null; - cy.log(cookie.value); + cy.log("cookie.value is: " + cookie.value); cy.location().should((loc) => { expect(loc.href).to.eq(loc.origin + "/applications"); @@ -319,13 +362,9 @@ Cypress.Commands.add("LoginFromAPI", (uname, pword) => { if (CURRENT_REPO === REPO.EE) { cy.wait(2000); } else { - cy.wait("@getMe"); - cy.wait("@applications").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); - cy.wait("@getReleaseItems"); + assertHelper.AssertNetworkStatus("getMe"); + assertHelper.AssertNetworkStatus("applications"); + assertHelper.AssertNetworkStatus("getReleaseItems"); } }); cy.wait(2000); //for the page elements to load! @@ -350,7 +389,19 @@ Cypress.Commands.add("DeletepageFromSideBar", () => { cy.wait(2000); }); -Cypress.Commands.add("LogOut", () => { +Cypress.Commands.add("LogOut", (toCheckgetPluginForm = true) => { + agHelper.WaitUntilAllToastsDisappear(); + //Since these are coming in every self-hosted 1st time login, commenting for CI runs + // agHelper.AssertElementAbsence( + // locators._specificToast("There was an unexpected error"), + // ); + // agHelper.AssertElementAbsence( + // locators._specificToast("Internal server error while processing request"), + // ); + if (CURRENT_REPO === REPO.CE) + toCheckgetPluginForm && + assertHelper.AssertNetworkResponseData("@getPluginForm", false); + cy.request({ method: "POST", url: "/api/v1/logout", @@ -670,7 +721,7 @@ Cypress.Commands.add("addDsl", (dsl) => { Cypress.Commands.add("DeleteAppByApi", () => { const appId = localStorage.getItem("applicationId"); if (appId !== null) { - cy.log(appId + "appId"); + cy.log("appId to delete is:" + appId); cy.request({ method: "DELETE", url: "api/v1/applications/" + appId, @@ -685,6 +736,24 @@ Cypress.Commands.add("DeleteAppByApi", () => { } }); +Cypress.Commands.add("DeleteWorkspaceByApi", () => { + const workspaceId = localStorage.getItem("workspaceId"); + if (workspaceId !== null) { + cy.log("workspaceId to delete is:" + workspaceId); + cy.request({ + method: "DELETE", + url: "api/v1/workspaces/" + workspaceId, + failOnStatusCode: false, + headers: { + "X-Requested-By": "Appsmith", + }, + }).then((response) => { + cy.log(response.body); + cy.log(response.status); + }); + } +}); + Cypress.Commands.add("togglebar", (value) => { cy.get(value).check({ force: true }).should("be.checked"); }); @@ -846,7 +915,7 @@ Cypress.Commands.add("changeButtonColor", (buttonColor) => { cy.get(widgetsPage.buttonColor) .click({ force: true }) .clear() - .type(buttonColor); + .type(buttonColor, { delay: 0 }); deployMode.DeployApp(); cy.get(widgetsPage.widgetBtn).should( "have.css", @@ -961,7 +1030,6 @@ Cypress.Commands.add("startServerAndRoutes", () => { cy.intercept("GET", "/api/v1/users/profile").as("getUser"); cy.intercept("GET", "/api/v1/plugins?workspaceId=*").as("getPlugins"); cy.intercept("POST", "/api/v1/logout").as("postLogout"); - cy.intercept("GET", "/api/v1/datasources?workspaceId=*").as("getDataSources"); cy.intercept("GET", "/api/v1/pages?*mode=EDIT").as("getPagesForCreateApp"); cy.intercept("GET", "/api/v1/pages?*mode=PUBLISHED").as("getPagesForViewApp"); @@ -984,6 +1052,9 @@ Cypress.Commands.add("startServerAndRoutes", () => { "makePageDefault", ); cy.intercept("DELETE", "/api/v1/applications/*").as("deleteApp"); + cy.intercept("POST", "/api/v1/applications/delete-apps").as( + "deleteMultipleApp", + ); cy.intercept("DELETE", "/api/v1/pages/*").as("deletePage"); //cy.intercept("POST", "/api/v1/datasources").as("createDatasource"); cy.intercept("DELETE", "/api/v1/datasources/*").as("deleteDatasource"); @@ -1085,6 +1156,7 @@ Cypress.Commands.add("startServerAndRoutes", () => { cy.intercept("GET", "/api/v1/admin/env").as("getEnvVariables"); cy.intercept("DELETE", "/api/v1/git/branch/app/*").as("deleteBranch"); cy.intercept("GET", "/api/v1/git/branch/app/*").as("getBranch"); + cy.intercept("POST", "/api/v1/git/create-branch/app/*").as("createBranch"); cy.intercept("GET", "/api/v1/git/status/app/*").as("gitStatus"); cy.intercept("PUT", "/api/v1/layouts/refactor").as("updateWidgetName"); cy.intercept("GET", "/api/v1/workspaces/*/members").as("getMembers"); @@ -1096,6 +1168,7 @@ Cypress.Commands.add("startServerAndRoutes", () => { ); cy.intercept("PUT", "/api/v1/datasources/*").as("updateDatasource"); cy.intercept("POST", "/api/v1/applications/ssh-keypair/*").as("generateKey"); + cy.intercept("GET", "/api/v1/applications/ssh-keypair/*").as("generatedKey"); cy.intercept("POST", "/api/v1/applications/snapshot/*").as("snapshotSuccess"); cy.intercept( { @@ -1108,9 +1181,9 @@ Cypress.Commands.add("startServerAndRoutes", () => { }, ).as("connectGitLocalRepo"); - cy.intercept({ - method: "PUT", - }).as("sucessSave"); + // cy.intercept({ + // method: "PUT", + // }).as("sucessSave"); cy.intercept("POST", "https://api.segment.io/v1/b", (req) => { req.reply({ @@ -1158,6 +1231,18 @@ Cypress.Commands.add("startServerAndRoutes", () => { }); }, ).as("productAlert"); + cy.intercept( + { + method: "GET", + url: /domain\/docs\.appsmith\.com\/token$/, + }, + { + statusCode: 200, + }, + ).as("docsCall"); + cy.intercept("POST", "/api/v1/datasources/*/schema-preview").as( + "schemaPreview", + ); }); Cypress.Commands.add("startErrorRoutes", () => { @@ -1203,77 +1288,59 @@ Cypress.Commands.add("ValidatePublishTableV2Data", (value) => { }); }); -Cypress.Commands.add( - "ValidatePaginateResponseUrlData", - (runTestCss, isNext) => { - cy.CheckAndUnfoldEntityItem("Queries/JS"); - cy.get(".t--entity-name").contains("Api2").click({ force: true }); - cy.wait(3000); - cy.NavigateToPaginationTab(); - cy.RunAPI(); - cy.get(ApiEditor.apiPaginationNextTest).click(); - cy.wait("@postExecute"); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(2000); - cy.get(runTestCss).click(); - cy.wait("@postExecute").then((interception) => { - let valueToTest = JSON.stringify( - interception.response.body.data.body[0].name, - ); +Cypress.Commands.add("ValidatePaginateResponseUrlData", (runTestCss) => { + cy.CheckAndUnfoldEntityItem("Queries/JS"); + cy.get(".t--entity-name").contains("Api2").click({ force: true }); + cy.wait(3000); + cy.NavigateToPaginationTab(); + cy.RunAPI(); + cy.get(ApiEditor.apiPaginationNextTest).click(); + cy.wait("@postExecute"); + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(2000); + cy.get(runTestCss).click(); + cy.wait(2000); + cy.xpath("//div[@class='tr'][1]//div[@class='td'][6]//span") + .invoke("text") + .then((valueToTest) => { // eslint-disable-next-line cypress/no-unnecessary-waiting cy.get(ApiEditor.ApiRunBtn).should("not.be.disabled"); cy.get(".t--entity-name").contains("Table1").click({ force: true }); cy.isSelectRow(0); - if (isNext) { - cy.wait("@postExecute").then((interception) => { - valueToTest = JSON.stringify( - interception.response.body.data.body[0].name, - ); - }); - } cy.readTabledata("0", "5").then((tabData) => { const tableData = tabData; - expect(`\"${tableData}\"`).to.equal(valueToTest); + expect(valueToTest).contains(tableData); }); }); - }, -); +}); -Cypress.Commands.add( - "ValidatePaginateResponseUrlDataV2", - (runTestCss, isNext) => { - cy.CheckAndUnfoldEntityItem("Queries/JS"); - cy.get(".t--entity-name").contains("Api2").click({ force: true }); - cy.wait(3000); - cy.NavigateToPaginationTab(); - cy.RunAPI(); - cy.get(ApiEditor.apiPaginationNextTest).click(); - cy.wait("@postExecute"); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(2000); - cy.get(runTestCss).click(); - cy.wait("@postExecute").then((interception) => { - let valueToTest = JSON.stringify( - interception.response.body.data.body[0].name, - ); +Cypress.Commands.add("ValidatePaginateResponseUrlDataV2", (runTestCss) => { + cy.CheckAndUnfoldEntityItem("Queries/JS"); + cy.get(".t--entity-name").contains("Api2").click({ force: true }); + cy.wait(3000); + cy.NavigateToPaginationTab(); + cy.RunAPI(); + cy.get(ApiEditor.apiPaginationNextTest).click(); + cy.wait("@postExecute"); + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(2000); + cy.get(runTestCss).click(); + cy.wait(2000); + cy.xpath("//div[@class='tr'][1]//div[@class='td'][6]//span") + .invoke("text") + .then((valueToTest) => { // eslint-disable-next-line cypress/no-unnecessary-waiting cy.get(ApiEditor.ApiRunBtn).should("not.be.disabled"); cy.get(".t--entity-name").contains("Table1").click({ force: true }); + cy.wait(2000); cy.isSelectRow(0); - if (isNext) { - cy.wait("@postExecute").then((interception) => { - valueToTest = JSON.stringify( - interception.response.body.data.body[0].name, - ); - }); - } cy.readTableV2data("0", "5").then((tabData) => { const tableData = tabData; - expect(`\"${tableData}\"`).to.equal(valueToTest); + cy.log(valueToTest); + expect(valueToTest).contains(tableData); }); }); - }, -); +}); Cypress.Commands.add("ValidatePaginationInputData", (valueToTest) => { cy.isSelectRow(0); @@ -1390,7 +1457,13 @@ Cypress.Commands.add("createSuperUser", () => { expect(interception.request.body).contains("signupForNewsletter=true"); }); } - cy.wait("@getWorkspace"); + + cy.wait(2000); + + if (CURRENT_REPO === REPO.CE) { + cy.get("#loading").should("not.exist"); + cy.get("#sidebar").should("be.visible"); + } cy.LogOut(); cy.wait(2000); @@ -2183,7 +2256,7 @@ Cypress.Commands.add("SelectFromMultiSelect", (options) => { }); Cypress.Commands.add("skipSignposting", () => { - onboarding.closeIntroModal(); + onboarding.skipSignposting(); }); Cypress.Commands.add("stubPricingPage", () => { diff --git a/app/client/cypress/support/dataSourceCommands.js b/app/client/cypress/support/dataSourceCommands.js index dafbfdfab8..f8e0bfbc45 100644 --- a/app/client/cypress/support/dataSourceCommands.js +++ b/app/client/cypress/support/dataSourceCommands.js @@ -85,39 +85,6 @@ Cypress.Commands.add("testSaveDatasource", (expectedRes = true) => { // .click(); }); -Cypress.Commands.add( - "fillMongoDatasourceForm", - (shouldAddTrailingSpaces = false) => { - const hostAddress = shouldAddTrailingSpaces - ? datasourceFormData["mongo-host"] + " " - : datasourceFormData["mongo-host"]; - // const databaseName = shouldAddTrailingSpaces - // ? datasourceFormData["mongo-databaseName"] + " " - // : datasourceFormData["mongo-databaseName"]; - cy.get(datasourceEditor["host"]).clear().type(hostAddress); - cy.get(datasourceEditor.port) - .clear() - .type(datasourceFormData["mongo-port"]); - //cy.get(datasourceEditor["port"]).type(datasourceFormData["mongo-port"]); - //cy.get(datasourceEditor["selConnectionType"]).click(); - //cy.contains(datasourceFormData["connection-type"]).click(); - //cy.get(datasourceEditor["defaultDatabaseName"]).type(databaseName);//is optional hence removing - cy.get(datasourceEditor["databaseName"]) - .clear() - .type(datasourceFormData["mongo-databaseName"]); - // cy.get(datasourceEditor["username"]).type( - // datasourceFormData["mongo-username"], - // ); - // cy.get(datasourceEditor["password"]).type( - // datasourceFormData["mongo-password"], - // ); - // cy.get(datasourceEditor["authenticationAuthtype"]).click(); - // cy.contains(datasourceFormData["mongo-authenticationAuthtype"]).click({ - // force: true, - // }); - }, -); - Cypress.Commands.add( "fillPostgresDatasourceForm", (shouldAddTrailingSpaces = false) => { @@ -334,14 +301,6 @@ Cypress.Commands.add("createAmazonS3Datasource", () => { cy.testSaveDatasource(); }); -Cypress.Commands.add("fillMongoDatasourceFormWithURI", () => { - cy.xpath(datasourceEditor["mongoUriDropdown"]).click().wait(500); - cy.xpath(datasourceEditor["mongoUriYes"]).click().wait(500); - cy.xpath(datasourceEditor["mongoUriInput"]).type( - datasourceFormData["mongo-uri"], - ); -}); - Cypress.Commands.add("ReconnectDatasource", (datasource) => { cy.xpath(`//span[text()='${datasource}']`).click(); }); diff --git a/app/client/cypress/support/e2e.js b/app/client/cypress/support/e2e.js index 34b1c44fd5..5631f3ac0c 100644 --- a/app/client/cypress/support/e2e.js +++ b/app/client/cypress/support/e2e.js @@ -22,28 +22,37 @@ import * as MESSAGES from "../../../client/src/ce/constants/messages.ts"; import "./ApiCommands"; // Import commands.js using ES2015 syntax: import "./commands"; -import { initLocalstorage } from "./commands"; +import { initLocalstorage, addIndexedDBKey } from "./commands"; import "./dataSourceCommands"; import "./gitSync"; import { initLocalstorageRegistry } from "./Objects/Registry"; import RapidMode from "./RapidMode.ts"; import "cypress-mochawesome-reporter/register"; +import installLogsCollector from "cypress-terminal-report/src/installLogsCollector"; +import { CURRENT_REPO, REPO } from "../fixtures/REPO"; import "./WorkspaceCommands"; import "./queryCommands"; import "./widgetCommands"; import "./themeCommands"; import "./AdminSettingsCommands"; +import "cypress-plugin-tab"; +import { + FEATURE_WALKTHROUGH_INDEX_KEY, + WALKTHROUGH_TEST_PAGE, +} from "./Constants.js"; /// -Cypress.on("uncaught:exception", () => { - // returning false here prevents Cypress from - // failing the test - return false; +installLogsCollector(); + +Cypress.on("uncaught:exception", (error) => { + //cy.log(error.message); + return false; // returning false here prevents Cypress from failing the test }); Cypress.on("fail", (error) => { - throw error; // throw error to have test still fail + cy.log(error.message); + throw error; // throw error to have test fail }); Cypress.env("MESSAGES", MESSAGES); @@ -81,6 +90,8 @@ before(function () { cy.visit("/setup/welcome", { timeout: 60000 }); cy.wait("@getMe"); cy.wait(2000); + const username = Cypress.env("USERNAME"); + const password = Cypress.env("PASSWORD"); cy.url().then((url) => { if (url.indexOf("setup/welcome") > -1) { cy.createSuperUser(); @@ -104,52 +115,39 @@ before(function () { Cypress.env("TESTPASSWORD4"), ); cy.LogOut(); + cy.LoginFromAPI(username, password); + } else if (url.indexOf("user/login") > -1) { + //Cypress.Cookies.preserveOnce("SESSION", "remember_token"); + cy.LoginFromAPI(username, password); + cy.wait(3000); } }); - //console.warn = () => {}; - //Cypress.Cookies.preserveOnce("SESSION", "remember_token"); - const username = Cypress.env("USERNAME"); - const password = Cypress.env("PASSWORD"); - cy.LoginFromAPI(username, password); - cy.wait("@getMe"); - cy.wait(3000); - cy.get(".t--applications-container .createnew") - .should("be.visible") - .should("be.enabled"); - cy.generateUUID().then((id) => { - cy.CreateAppInFirstListedWorkspace(id); - localStorage.setItem("AppName", id); - }); + if (CURRENT_REPO === REPO.EE) { + cy.wait(2000); + cy.url().then((url) => { + if (url.indexOf("/license") > -1) { + cy.validateLicense(); + } + }); + } + if (!Cypress.currentTest.titlePath[0].includes(WALKTHROUGH_TEST_PAGE)) { + // Adding key FEATURE_WALKTHROUGH (which is used to check if the walkthrough is already shown to the user or not) for non walkthrough cypress tests (to not show walkthrough) + addIndexedDBKey(FEATURE_WALKTHROUGH_INDEX_KEY, { + ab_ds_binding_enabled: true, + ab_ds_schema_enabled: true, + binding_widget: true, + }); + } + //console.warn = () => {}; + + cy.CreateNewAppInNewWorkspace(); //Creating new workspace and app cy.fixture("TestDataSet1").then(function (data) { this.dataSet = data; }); }); -// before(function () { -// if (RapidMode.config.enabled) { -// return; -// } -// // //console.warn = () => {}; -// // //Cypress.Cookies.preserveOnce("SESSION", "remember_token"); -// // const username = Cypress.env("USERNAME"); -// // const password = Cypress.env("PASSWORD"); -// // cy.LoginFromAPI(username, password); -// // cy.wait(3000); -// // cy.get(".t--applications-container .createnew") -// // .should("be.visible") -// // .should("be.enabled"); -// // cy.generateUUID().then((id) => { -// // cy.CreateAppInFirstListedWorkspace(id); -// // localStorage.setItem("AppName", id); -// // }); - -// // cy.fixture("TestDataSet1").then(function (data) { -// // this.dataSet = data; -// // }); -// }); - beforeEach(function () { //cy.window().then((win) => (win.onbeforeunload = undefined)); if (!navigator.userAgent.includes("Cypress")) { @@ -171,8 +169,9 @@ after(function () { } //-- Deleting the application by Api---// cy.DeleteAppByApi(); + cy.DeleteWorkspaceByApi(); //-- LogOut Application---// - cy.LogOut(); + //cy.LogOut(false); // Commenting until Upgrade Appsmith cases are fixed // const tedUrl = "http://localhost:5001/v1/parent/cmd"; // cy.log("Start the appsmith container"); diff --git a/app/client/cypress/support/gitSync.js b/app/client/cypress/support/gitSync.js index a543043350..0447218586 100644 --- a/app/client/cypress/support/gitSync.js +++ b/app/client/cypress/support/gitSync.js @@ -9,7 +9,8 @@ import { ObjectsRegistry } from "../support/Objects/Registry"; let gitSync = ObjectsRegistry.GitSync, agHelper = ObjectsRegistry.AggregateHelper, - dataManager = ObjectsRegistry.DataManager; + dataManager = ObjectsRegistry.DataManager, + assertHelper = ObjectsRegistry.AssertHelper; const commonLocators = require("../locators/commonlocators.json"); const GITHUB_API_BASE = "https://api.github.com"; @@ -303,7 +304,8 @@ Cypress.Commands.add("merge", (destinationBranch) => { cy.get(gitSyncLocators.mergeBranchDropdownDestination).click(); cy.get(commonLocators.dropdownmenu).contains(destinationBranch).click(); agHelper.AssertElementAbsence(gitSync._checkMergeability, 35000); - cy.wait("@mergeStatus", { timeout: 35000 }).should( + assertHelper.WaitForNetworkCall("mergeStatus"); + cy.get("@mergeStatus").should( "have.nested.property", "response.body.data.isMergeAble", true, @@ -311,11 +313,7 @@ Cypress.Commands.add("merge", (destinationBranch) => { cy.wait(2000); cy.contains(Cypress.env("MESSAGES").NO_MERGE_CONFLICT()); cy.get(gitSyncLocators.mergeCTA).click(); - cy.wait("@mergeBranch", { timeout: 35000 }).should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); //adding timeout since merge is taking longer sometimes + assertHelper.AssertNetworkStatus("mergeBranch", 200); cy.contains(Cypress.env("MESSAGES").MERGED_SUCCESSFULLY()); }); @@ -408,20 +406,21 @@ Cypress.Commands.add( Cypress.Commands.add("gitDiscardChanges", () => { cy.get(gitSyncLocators.bottomBarCommitButton).click(); cy.get(gitSyncLocators.discardChanges).should("be.visible"); - //cy.wait(6000); cy.get(gitSyncLocators.discardChanges) .children() .should("have.text", "Discard & pull"); - cy.get(gitSyncLocators.discardChanges).click(); cy.contains(Cypress.env("MESSAGES").DISCARD_CHANGES_WARNING()); - cy.get(gitSyncLocators.discardChanges) .children() .should("have.text", "Are you sure?"); cy.get(gitSyncLocators.discardChanges).click(); cy.contains(Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES()); cy.wait(2000); + assertHelper.AssertContains( + "Unable to import application in workspace", + "not.exist", + ); cy.validateToastMessage("Discarded changes successfully."); }); diff --git a/app/client/cypress/tsconfig.json b/app/client/cypress/tsconfig.json index 2ed43b3a40..1e80a45b6e 100644 --- a/app/client/cypress/tsconfig.json +++ b/app/client/cypress/tsconfig.json @@ -32,5 +32,5 @@ "noFallthroughCasesInSwitch": true, "types": ["cypress", "node", "cypress-tags", "cypress-real-events"] }, - "include": ["/**/*.ts", "../packages/rts/src/version.js"] + "include": ["./", "../packages/rts/src/version.js"] } diff --git a/app/client/cypress_ci-toremove.json b/app/client/cypress_ci-toremove.json deleted file mode 100644 index a4c1d982da..0000000000 --- a/app/client/cypress_ci-toremove.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "baseUrl": "http://localhost/", - "defaultCommandTimeout": 20000, - "requestTimeout": 21000, - "responseTimeout": 20000, - "pageLoadTimeout": 30000, - "videoUploadOnPasses": false, - "videoCompression": false, - "numTestsKeptInMemory": 10, - "reporterOptions": { - "reportDir": "results", - "overwrite": false, - "html": true, - "json": false - }, - "chromeWebSecurity": false, - "viewportHeight": 1100, - "viewportWidth": 1400, - "retries": { - "runMode": 0, - "openMode": 0 - } -} diff --git a/app/client/cypress_ci.config.ts b/app/client/cypress_ci.config.ts index f417ed4b53..d54d3bb449 100644 --- a/app/client/cypress_ci.config.ts +++ b/app/client/cypress_ci.config.ts @@ -5,8 +5,7 @@ export default defineConfig({ requestTimeout: 60000, responseTimeout: 60000, pageLoadTimeout: 60000, - videoUploadOnPasses: false, - videoCompression: false, + video: true, numTestsKeptInMemory: 5, experimentalMemoryManagement: true, reporterOptions: { @@ -34,6 +33,8 @@ export default defineConfig({ "cypress/e2e/**/spec_utility.ts", "cypress/e2e/GSheet/**/**/*", "cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts", + "cypress/e2e/Regression/ClientSide/CommunityTemplate/*", + "cypress/e2e/Regression/ServerSide/Datasources/ElasticSearch_Basic_Spec.ts", ], }, }); diff --git a/app/client/cypress_ci_custom.config.ts b/app/client/cypress_ci_custom.config.ts index 2b1bedc8da..9ffd3a80b2 100644 --- a/app/client/cypress_ci_custom.config.ts +++ b/app/client/cypress_ci_custom.config.ts @@ -6,7 +6,7 @@ export default defineConfig({ requestTimeout: 60000, responseTimeout: 60000, pageLoadTimeout: 60000, - videoUploadOnPasses: false, + video: true, numTestsKeptInMemory: 5, experimentalMemoryManagement: true, reporter: "cypress-mochawesome-reporter", @@ -20,7 +20,7 @@ export default defineConfig({ saveAllAttempts: true, }, chromeWebSecurity: false, - viewportHeight: 1100, + viewportHeight: 1200, viewportWidth: 1400, scrollBehavior: "center", retries: { @@ -50,6 +50,16 @@ export default defineConfig({ }, specPattern: "cypress/e2e/**/*.{js,ts}", testIsolation: false, - excludeSpecPattern: "cypress/e2e/**/spec_utility.ts", + excludeSpecPattern: [ + "cypress/e2e/**/spec_utility.ts", + "cypress/e2e/Regression/ClientSide/CommunityTemplate/*", + "cypress/e2e/GSheet/**/**/*", + "cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts", + "cypress/e2e/EE/Enterprise/MultipleEnv/ME_airtable_spec.ts", + "cypress/e2e/Regression/ServerSide/Datasources/ElasticSearch_Basic_Spec.ts", + "cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts", + "cypress/e2e/Regression/ClientSide/Widgets/Others/MapWidget_Spec.ts", + "cypress/e2e/Sanity/Datasources/MsSQL_Basic_Spec.ts", + ], }, }); diff --git a/app/client/cypress_ci_hosted.config.ts b/app/client/cypress_ci_hosted.config.ts index 857c43da00..fd3f80f2c0 100644 --- a/app/client/cypress_ci_hosted.config.ts +++ b/app/client/cypress_ci_hosted.config.ts @@ -1,19 +1,24 @@ import { defineConfig } from "cypress"; +import fs from "fs"; export default defineConfig({ defaultCommandTimeout: 30000, requestTimeout: 60000, responseTimeout: 60000, pageLoadTimeout: 60000, - videoUploadOnPasses: false, videoCompression: false, + video: true, numTestsKeptInMemory: 5, experimentalMemoryManagement: true, + reporter: "cypress-mochawesome-reporter", reporterOptions: { reportDir: "results", - overwrite: false, - html: true, - json: false, + charts: true, + reportPageTitle: "Cypress-report", + videoOnFailOnly: true, + embeddedScreenshots: true, + inlineAssets: true, + saveAllAttempts: true, }, chromeWebSecurity: false, viewportHeight: 1100, @@ -26,9 +31,30 @@ export default defineConfig({ e2e: { baseUrl: "https://regression.test.appsmith.com/", setupNodeEvents(on, config) { + require("cypress-mochawesome-reporter/plugin")(on); + on( + "after:spec", + (spec: Cypress.Spec, results: CypressCommandLine.RunResult) => { + if (results && results.video) { + // Do we have failures for any retry attempts? + const failures = results.tests.some((test) => + test.attempts.some((attempt) => attempt.state === "failed"), + ); + if (!failures) { + // delete the video if the spec passed and no tests retried + fs.unlinkSync(results.video); + } + } + }, + ); return require("./cypress/plugins/index.js")(on, config); }, - specPattern: "cypress/e2e/**/*.{js,ts}", + specPattern: [ + "cypress/e2e/Sanity/Datasources/Airtable_Basic_Spec.ts", + "cypress/e2e/GSheet/**/**/*", + "cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts", + "cypress/e2e/Regression/ClientSide/Widgets/Others/MapWidget_Spec.ts", + ], testIsolation: false, excludeSpecPattern: ["cypress/e2e/**/spec_utility.ts"], }, diff --git a/app/client/docker/templates/nginx-app.conf.template b/app/client/docker/templates/nginx-app.conf.template index 6fc517d399..4b19efc7c1 100644 --- a/app/client/docker/templates/nginx-app.conf.template +++ b/app/client/docker/templates/nginx-app.conf.template @@ -50,7 +50,12 @@ server { sub_filter __APPSMITH_ZIPY_SDK_KEY__ '${APPSMITH_ZIPY_SDK_KEY}'; sub_filter __APPSMITH_HIDE_WATERMARK__ '${APPSMITH_HIDE_WATERMARK}'; sub_filter __APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX__ '${APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX}'; - sub_filter __APPSMITH_BMAP_AK__ '${APPSMITH_BMAP_AK}'; + sub_filter __APPSMITH_NEW_RELIC_ACCOUNT_ID__ '${APPSMITH_NEW_RELIC_ACCOUNT_ID}'; + sub_filter __APPSMITH_NEW_RELIC_APPLICATION_ID__ '${APPSMITH_NEW_RELIC_APPLICATION_ID}'; + sub_filter __APPSMITH_NEW_RELIC_BROWSER_AGENT_LICENSE_KEY__ '${APPSMITH_NEW_RELIC_BROWSER_AGENT_LICENSE_KEY}'; + sub_filter __APPSMITH_NEW_RELIC_ACCOUNT_ENABLE__ '${APPSMITH_NEW_RELIC_ACCOUNT_ENABLE}'; + sub_filter __APPSMITH_NEW_RELIC_OTLP_LICENSE_KEY__ '${APPSMITH_NEW_RELIC_OTLP_LICENSE_KEY}'; + } location /favicon.ico { diff --git a/app/client/generators/widget/templates/widget/index.js.hbs b/app/client/generators/widget/templates/widget/index.js.hbs index 640a525193..d5ba5ace2d 100644 --- a/app/client/generators/widget/templates/widget/index.js.hbs +++ b/app/client/generators/widget/templates/widget/index.js.hbs @@ -1,7 +1,7 @@ import React from "react"; import BaseWidget, { WidgetProps, WidgetState } from "widgets/BaseWidget"; -import { DerivedPropertiesMap } from "utils/WidgetFactory"; +import { DerivedPropertiesMap } from "WidgetProvider/factory"; import {{name}}Component from "../component"; diff --git a/app/client/jest.config.js b/app/client/jest.config.js index 3fd4b33709..7006556898 100644 --- a/app/client/jest.config.js +++ b/app/client/jest.config.js @@ -17,7 +17,7 @@ module.exports = { moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node", "css"], moduleDirectories: ["node_modules", "src", "test"], transformIgnorePatterns: [ - "/node_modules/(?!codemirror|design-system|design-system-old|react-dnd|dnd-core|@babel|(@blueprintjs)|@github|lodash-es|@draft-js-plugins|react-documents|linkedom|assert-never)", + "/node_modules/(?!codemirror|konva|design-system|design-system-old|react-dnd|dnd-core|@babel|(@blueprintjs)|@github|lodash-es|@draft-js-plugins|react-documents|linkedom|assert-never)", ], moduleNameMapper: { "\\.(css|less)$": "/test/__mocks__/styleMock.js", @@ -52,6 +52,7 @@ module.exports = { "^@blueprintjs/select$": "/node_modules/@blueprintjs/select/lib/esnext", "design-system": "/node_modules/design-system/build", + "^canvas$": "jest-canvas-mock", }, globals: { "ts-jest": { @@ -82,6 +83,13 @@ module.exports = { apiKey: parseConfig("__APPSMITH_SEGMENT_KEY__"), ceKey: parseConfig("__APPSMITH_SEGMENT_CE_KEY__"), }, + newRelic:{ + enableNewRelic: parseConfig("__APPSMITH_NEW_RELIC_ACCOUNT_ENABLE__"), + accountId: parseConfig("__APPSMITH_NEW_RELIC_ACCOUNT_ID__"), + applicationId: parseConfig("__APPSMITH_NEW_RELIC_APPLICATION_ID__"), + browserAgentlicenseKey: parseConfig("__APPSMITH_NEW_RELIC_BROWSER_AGENT_LICENSE_KEY__"), + otlpLicenseKey: parseConfig("__APPSMITH_NEW_RELIC_OTLP_LICENSE_KEY__"), + }, fusioncharts: { licenseKey: parseConfig("__APPSMITH_FUSIONCHARTS_LICENSE_KEY__"), }, @@ -103,8 +111,6 @@ module.exports = { }, intercomAppID: "APP_ID", mailEnabled: parseConfig("__APPSMITH_MAIL_ENABLED__"), - - hideWatermark: parseConfig("__APPSMITH_HIDE_WATERMARK__"), disableIframeWidgetSandbox: parseConfig( "__APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX__", ), diff --git a/app/client/package.json b/app/client/package.json index 8ab7987918..27ed05ae98 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -21,7 +21,7 @@ "start-win-log": "set BROWSER=none&& set EXTEND_ESLINT=true&& set REACT_APP_ENVIRONMENT=DEVELOPMENT&& set REACT_APP_CLIENT_LOG_LEVEL=debug&& craco --max_old_space_size=4096 start", "start-win": "set BROWSER=none&& set EXTEND_ESLINT=true&& set REACT_APP_ENVIRONMENT=DEVELOPMENT&& craco --max_old_space_size=4096 start", "start-cloudos": "set BROWSER=none&& set EXTEND_ESLINT=true&& set REACT_APP_ENVIRONMENT=DEVELOPMENT&& set REACT_APP_IN_CLOUDOS=true&& craco --max_old_space_size=4096 start", - "start": "yarn workspace @shared/dsl build && yarn workspace @shared/ast build && BROWSER=none EXTEND_ESLINT=true REACT_APP_ENVIRONMENT=DEVELOPMENT REACT_APP_CLIENT_LOG_LEVEL=debug HOST=dev.appsmith.com craco --max_old_space_size=7168 start", + "start": "BROWSER=none EXTEND_ESLINT=true REACT_APP_ENVIRONMENT=DEVELOPMENT REACT_APP_CLIENT_LOG_LEVEL=debug HOST=dev.appsmith.com craco --max_old_space_size=7168 start", "build": "./build.sh", "build-win": "bash ./build.sh", "build-cloudos": "set REACT_APP_IN_CLOUDOS=true&& set REACT_APP_WORK_ENV=cloudos&& bash ./build.sh", @@ -43,7 +43,7 @@ "preinstall": "set CURRENT_SCOPE=client node ../shared/build-shared-dep.js", "install": "node cypress/apply-patches.js", "storybook": "yarn workspace @design-system/storybook storybook", - "lint": "eslint --cache --ext .js,.ts,.tsx ./src && eslint --cache --ext .js,.ts ./cypress", + "lint": "eslint --cache ./src && cd ./cypress && eslint -c .eslintrc.json --cache ./", "g:lint": "cd $INIT_CWD && eslint --cache .", "lint:ci": "yarn workspaces foreach -ptv run lint", "prettier": "prettier --check ./src && prettier --check ./cypress", @@ -61,6 +61,7 @@ "@blueprintjs/icons": "3.22.0", "@blueprintjs/popover2": "^0.5.0", "@blueprintjs/select": "^3.10.0", + "@design-system/storybook": "workspace:^", "@design-system/theming": "workspace:^", "@design-system/widgets": "workspace:^", "@design-system/widgets-old": "workspace:^", @@ -78,6 +79,14 @@ "@mantine/hooks": "^5.10.1", "@pind/designable-formily-antd": "^2.0.0-beta.6", "@pind/designable-react-settings-form": "^2.0.0-beta.6", + "@opentelemetry/auto-instrumentations-web": "^0.33.2", + "@opentelemetry/context-zone": "^1.17.1", + "@opentelemetry/exporter-trace-otlp-proto": "^0.44.0", + "@opentelemetry/instrumentation": "^0.44.0", + "@opentelemetry/resources": "^1.17.1", + "@opentelemetry/sdk-trace-base": "^1.17.1", + "@opentelemetry/sdk-trace-web": "^1.17.1", + "@opentelemetry/semantic-conventions": "^1.17.1", "@sentry/react": "^6.2.4", "@sentry/tracing": "^6.2.4", "@shared/ast": "workspace:^", @@ -105,6 +114,7 @@ "antd": "^5.2.2", "assert-never": "^1.2.1", "astring": "^1.7.5", + "aws-sdk": "^2.1443.0", "axios": "^0.27.2", "classnames": "^2.3.1", "clsx": "^1.2.1", @@ -116,27 +126,24 @@ "craco-alias": "^2.1.1", "craco-babel-loader": "^1.0.4", "craco-less": "2.1.0-alpha.0", + "cssnano": "^6.0.1", "cypress-log-to-output": "^1.1.2", "dayjs": "^1.10.6", "deep-diff": "^1.0.2", - "delayed-stream": "^1.0.0", - "design-system": "npm:@appsmithorg/design-system@2.1.28", - "design-system-old": "npm:@appsmithorg/design-system-old@1.1.11", + "design-system": "npm:@appsmithorg/design-system@2.1.30", + "design-system-old": "npm:@appsmithorg/design-system-old@1.1.14", "downloadjs": "^1.4.7", "draft-js": "^0.11.7", "echarts": "^5.4.2", "echarts-gl": "^2.0.9", - "eslint-config-react-app": "7.0.1", - "exceljs": "^4.3.0", "fast-deep-equal": "^3.1.3", "fast-sort": "^3.4.0", - "fast-xml-parser": "^3.17.5", "fastdom": "^1.0.11", "focus-trap-react": "^8.9.2", "fuse.js": "^3.4.5", "fusioncharts": "^3.18.0", "fusionmaps": "^3.18.0", - "graphql": "^16.3.0", + "graphql": "^16.8.1", "history": "^4.10.1", "http-proxy": "^1.18.1", "immer": "^9.0.6", @@ -149,6 +156,7 @@ "js-sha256": "^0.9.0", "jshint": "^2.13.4", "klona": "^2.0.5", + "konva": "8.0.1", "libphonenumber-js": "^1.9.44", "linkedom": "^0.14.20", "localforage": "^1.7.3", @@ -197,6 +205,7 @@ "react-instantsearch-dom": "^6.4.0", "react-intl": "^5.20.3", "react-json-view": "^1.21.3", + "react-konva": "17.0.2-6", "react-masonry-css": "^1.0.16", "react-media-recorder": "^1.6.1", "react-modal": "^3.15.1", @@ -221,7 +230,7 @@ "react-tabs": "^3.0.0", "react-timer-hook": "^3.0.4", "react-use-gesture": "^7.0.4", - "react-virtuoso": "^1.9.0", + "react-virtuoso": "^4.5.0", "react-webcam": "^7.0.1", "react-window": "^1.8.6", "react-zoom-pan-pinch": "^1.6.1", @@ -238,6 +247,7 @@ "socket.io-client": "^4.5.4", "sql-formatter": "12.2.0", "styled-components": "^5.3.6", + "tailwindcss": "^3.3.3", "tern": "^0.21.0", "tinycolor2": "^1.4.2", "to-json-schema": "^0.2.5", @@ -264,6 +274,7 @@ "@babel/helper-string-parser": "^7.19.4", "@craco/craco": "^7.0.0-alpha.7", "@faker-js/faker": "^7.4.0", + "@octokit/rest": "^20.0.1", "@peculiar/webcrypto": "^1.4.3", "@redux-saga/testing-utils": "^1.1.5", "@sentry/webpack-plugin": "^1.18.9", @@ -285,6 +296,7 @@ "@types/node": "^10.12.18", "@types/node-forge": "^0.10.0", "@types/object-hash": "^2.2.1", + "@types/pg": "^8.10.2", "@types/prismjs": "^1.16.1", "@types/react": "^17.0.2", "@types/react-beautiful-dnd": "^11.0.4", @@ -312,10 +324,11 @@ "@types/tinycolor2": "^1.4.2", "@types/to-json-schema": "^0.2.1", "@types/toposort": "^2.0.3", + "@types/uuid": "^9.0.5", "@types/webfontloader": "1.6.33", "@types/zipcelx": "^1.5.0", - "@typescript-eslint/eslint-plugin": "^5.54.1", - "@typescript-eslint/parser": "^5.54.1", + "@typescript-eslint/eslint-plugin": "^6.7.4", + "@typescript-eslint/parser": "^6.7.4", "babel-plugin-lodash": "^3.3.4", "babel-plugin-module-resolver": "^4.1.0", "chalk": "^4.1.1", @@ -323,7 +336,7 @@ "cra-bundle-analyzer": "^0.1.0", "cross-env": "^7.0.3", "cy-verify-downloads": "^0.0.5", - "cypress": "^12.17.4", + "cypress": "13.3.1", "cypress-file-upload": "^4.1.1", "cypress-image-snapshot": "^4.0.1", "cypress-mochawesome-reporter": "^3.5.1", @@ -332,22 +345,22 @@ "cypress-plugin-tab": "^1.0.5", "cypress-real-events": "^1.8.1", "cypress-tags": "^1.1.2", + "cypress-terminal-report": "^5.3.6", "cypress-wait-until": "^1.7.2", "cypress-xpath": "^1.6.0", "diff": "^5.0.0", "dotenv": "^8.1.0", - "eslint": "^8.42.0", - "eslint-config-prettier": "^8.6.0", - "eslint-import-resolver-babel-module": "^5.3.1", - "eslint-plugin-cypress": "^2.11.2", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-jest": "^27.2.1", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "^7.30.0", - "eslint-plugin-react-hooks": "^2.3.0", - "eslint-plugin-sort-destructure-keys": "^1.3.5", - "eslint-plugin-storybook": "^0.6.11", - "eslint-webpack-plugin": "^4.0.1", + "eslint": "^8.51.0", + "eslint-config-prettier": "^9.0.0", + "eslint-import-resolver-babel-module": "^5.3.2", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jest": "^27.4.2", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-sort-destructure-keys": "^1.5.0", + "eslint-plugin-storybook": "^0.6.15", "esm": "^3.2.25", "factory.ts": "^0.5.1", "fork-ts-checker-webpack-plugin": "^7.2.0", @@ -357,12 +370,20 @@ "jest-environment-jsdom": "^27.4.1", "jest-styled-components": "^7.0.8", "json5": "^2.2.3", - "lint-staged": "^13.2.0", + "lint-staged": "^14.0.1", "msw": "^0.28.0", + "pg": "^8.11.3", "plop": "^3.1.1", "postcss-pageplug-pxtorem": "^0.0.1", + "postcss": "8.4.31", + "postcss-at-rules-variables": "^0.3.0", + "postcss-each": "^1.1.0", + "postcss-import": "^15.1.0", + "postcss-modules-values": "^4.0.0", + "postcss-nesting": "^12.0.1", + "postcss-url": "^10.1.3", "postinstall-postinstall": "^2.1.0", - "prettier": "^2.8.6", + "prettier": "^3.0.3", "prop-types": "^15.8.1", "raw-loader": "^4.0.2", "react-is": "^16.12.0", @@ -412,6 +433,8 @@ "@blueprintjs/core@^3.47.0": "patch:@blueprintjs/core@npm%3A3.47.0#./.yarn/patches/@blueprintjs-core-npm-3.47.0-a5bc1ea927.patch", "@blueprintjs/icons": "3.22.0", "@types/react": "^17.0.2", - "rc-select": "14.4.3" + "rc-select": "14.4.3", + "postcss": "8.4.31", + "@react-types/shared": "3.19.0" } } diff --git a/app/client/packages/ast/.eslintrc.json b/app/client/packages/ast/.eslintrc.json index f6cf7cd422..d17162040c 100644 --- a/app/client/packages/ast/.eslintrc.json +++ b/app/client/packages/ast/.eslintrc.json @@ -2,6 +2,7 @@ "extends": ["../../.eslintrc.base.json"], "ignorePatterns": ["build"], "rules": { + "@typescript-eslint/strict-boolean-expressions": "off", "@typescript-eslint/no-explicit-any": "off" } } diff --git a/app/client/packages/ast/index.ts b/app/client/packages/ast/index.ts index 1c04b33a72..60e86927a5 100644 --- a/app/client/packages/ast/index.ts +++ b/app/client/packages/ast/index.ts @@ -20,6 +20,7 @@ import { getFunctionalParamsFromNode, isTypeOfFunction, isFunctionPresent, + getMemberExpressionObjectFromProperty, } from "./src"; // constants @@ -133,4 +134,5 @@ export { isJSFunctionProperty, isFunctionPresent, PeekOverlayExpressionIdentifier, + getMemberExpressionObjectFromProperty, }; diff --git a/app/client/packages/ast/package.json b/app/client/packages/ast/package.json index 4d2a2d6e9f..e7e50e549f 100644 --- a/app/client/packages/ast/package.json +++ b/app/client/packages/ast/package.json @@ -3,23 +3,14 @@ "private": true, "version": "1.0.0", "description": "", + "main": "./index.ts", "scripts": { "test:unit": "jest -b --colors --no-cache --silent --coverage --collectCoverage=true --coverageDirectory='./' --coverageReporters='json-summary'", "test:jest": "jest --watch", "lint": "yarn g:lint", "prettier": "yarn g:prettier", - "build": "rollup -c", "start": "rollup -c", - "postinstall": "yarn build" - }, - "main": "build/index.js", - "module": "build/index.es.js", - "types": "build/index.d.ts", - "files": [ - "build" - ], - "publishConfig": { - "directory": "build" + "build": "rollup -c" }, "dependencies": { "@babel/runtime": "^7.21.0", @@ -47,7 +38,5 @@ "@typescript-eslint/parser": "^5.25.0", "jest": "29.0.3", "ts-jest": "29.0.1" - }, - "author": "", - "license": "ISC" + } } diff --git a/app/client/packages/ast/src/actionCreator/index.ts b/app/client/packages/ast/src/actionCreator/index.ts index f717b9770f..f3b89c53ff 100644 --- a/app/client/packages/ast/src/actionCreator/index.ts +++ b/app/client/packages/ast/src/actionCreator/index.ts @@ -1119,7 +1119,7 @@ export function setCatchBlockInQuery( ); if (!catchCallExpressionInGivenQuery) { const expression = klona( - thenCallExpressionInGivenQuery || rootCallExpression, + thenCallExpressionInGivenQuery ?? rootCallExpression, ); const callExpression = { type: NodeTypes.CallExpression, diff --git a/app/client/packages/ast/src/index.test.ts b/app/client/packages/ast/src/index.test.ts index 265ba2b531..ab53bce6a7 100644 --- a/app/client/packages/ast/src/index.test.ts +++ b/app/client/packages/ast/src/index.test.ts @@ -1,5 +1,9 @@ import { parseJSObject } from "../index"; -import { extractIdentifierInfoFromCode, isFunctionPresent } from "../src/index"; +import { + extractIdentifierInfoFromCode, + getMemberExpressionObjectFromProperty, + isFunctionPresent, +} from "../src/index"; describe("getAllIdentifiers", () => { it("works properly", () => { @@ -690,3 +694,83 @@ describe("isFunctionPresent", () => { expect(result).toBe(true); }); }); + +describe("getMemberExpressionObjectFromProperty", () => { + it("returns an empty array for empty property name", () => { + const code = `function(){ + const test = Api1.data.test + return "Favour" + }`; + const propertyName = ""; + const actualResponse = getMemberExpressionObjectFromProperty( + propertyName, + code, + ); + expect(actualResponse).toStrictEqual([]); + }); + it("returns an empty array for invalid js", () => { + const code = `function(){ + const test = Api1.data.test + return "Favour" + `; + const propertyName = "test"; + const actualResponse = getMemberExpressionObjectFromProperty( + propertyName, + code, + ); + expect(actualResponse).toStrictEqual([]); + }); + it("returns correct member expression object(s)", () => { + const testData = [ + { + code: `function(){ + const test = Api1.data.test + return "Favour" + }`, + propertyName: "test", + expectedResponse: ["Api1.data"], + }, + { + code: `function(){ + const test = Api1.data.test; + Button1.test; + return "Favour" + }`, + propertyName: "test", + expectedResponse: ["Api1.data", "Button1"], + }, + { + code: `function(){ + // const test = Api1.data.test + return "Favour" + }`, + propertyName: "test", + expectedResponse: [], + }, + { + code: `function(){ + const test = Api1.data.test.now + return "Favour" + }`, + propertyName: "test", + expectedResponse: ["Api1.data"], + }, + { + code: `function(){ + const test = Api1.data["test"] + return "Favour" + }`, + propertyName: "test", + expectedResponse: ["Api1.data"], + }, + ]; + + for (const testDatum of testData) { + const actualResponse = getMemberExpressionObjectFromProperty( + testDatum.propertyName, + testDatum.code, + ); + expect(actualResponse).toStrictEqual(testDatum.expectedResponse); + } + }); +}); diff --git a/app/client/packages/ast/src/index.ts b/app/client/packages/ast/src/index.ts index 6203086a0a..cfb5a2d196 100644 --- a/app/client/packages/ast/src/index.ts +++ b/app/client/packages/ast/src/index.ts @@ -2,10 +2,11 @@ import type { Node, SourceLocation, Options, Comment } from "acorn"; import { parse } from "acorn"; import { ancestor, simple } from "acorn-walk"; import { ECMA_VERSION, NodeTypes } from "./constants"; -import { has, isFinite, isString, toPath } from "lodash"; -import { isTrueObject, sanitizeScript } from "./utils"; +import { has, isFinite, isNil, isString, toPath } from "lodash"; +import { getStringValue, isTrueObject, sanitizeScript } from "./utils"; import { jsObjectDeclaration } from "./jsObject"; import { attachComments } from "astravel"; +import { generate } from "astring"; /* * Valuable links: * @@ -142,12 +143,12 @@ export interface BlockStatementNode extends Node { body: [Node]; } -type NodeList = { +interface NodeList { references: Set; functionalParams: Set; variableDeclarations: Set; identifierList: Array; -}; +} // https://github.com/estree/estree/blob/master/es5.md#property export interface PropertyNode extends Node { @@ -185,10 +186,10 @@ export type NodeWithLocation = NodeType & { type AstOptions = Omit; -type EntityRefactorResponse = { +interface EntityRefactorResponse { isSuccess: boolean; body: { script: string; refactorCount: number } | { error: string }; -}; +} /* We need these functions to typescript casts the nodes with the correct types */ export const isIdentifierNode = (node: Node): node is IdentifierNode => { @@ -507,7 +508,10 @@ export const entityRefactorFromCode = ( } }; -export type functionParam = { paramName: string; defaultValue: unknown }; +export interface functionParam { + paramName: string; + defaultValue: unknown; +} export const getFunctionalParamsFromNode = ( node: @@ -584,9 +588,8 @@ export interface MemberExpressionData { export interface AssignmentExpressionData { property: NodeWithLocation; - object: NodeWithLocation; - start: number; - end: number; + object: NodeWithLocation; + parentNode: NodeWithLocation; } export interface AssignmentExpressionNode extends Node { @@ -705,15 +708,12 @@ export const extractExpressionsFromCode = ( ) return; - const { object, property } = node.left as MemberExpressionNode; - if (!isIdentifierNode(object)) return; - if (!(object.name in data)) return; + const { object, property } = node.left; assignmentExpressionsData.add({ object, property, - start: node.start, - end: node.end, + parentNode: node, } as AssignmentExpressionData); }, }); @@ -886,3 +886,34 @@ export const isFunctionPresent = ( return false; } }; + +export function getMemberExpressionObjectFromProperty( + propertyName: string, + code: string, + evaluationVersion = 2, +) { + if (!propertyName) return []; + const memberExpressionObjects = new Set(); + let ast: Node = { end: 0, start: 0, type: "" }; + try { + const sanitizedScript = sanitizeScript(code, evaluationVersion); + const wrappedCode = wrapCode(sanitizedScript); + ast = getAST(wrappedCode, { locations: true }); + simple(ast, { + MemberExpression(node: Node) { + const { object, property } = node as MemberExpressionNode; + if (!isLiteralNode(property) && !isIdentifierNode(property)) return; + const propName = isLiteralNode(property) + ? property.value + : property.name; + if (!isNil(propName) && getStringValue(propName) === propertyName) { + const memberExpressionObjectString = generate(object); + memberExpressionObjects.add(memberExpressionObjectString); + } + }, + }); + return Array.from(memberExpressionObjects); + } catch (e) { + return []; + } +} diff --git a/app/client/packages/ast/src/peekOverlay/index.ts b/app/client/packages/ast/src/peekOverlay/index.ts index d9a4473816..c9d0efec2c 100644 --- a/app/client/packages/ast/src/peekOverlay/index.ts +++ b/app/client/packages/ast/src/peekOverlay/index.ts @@ -37,7 +37,7 @@ export class PeekOverlayExpressionIdentifier { this.parsedScript = undefined; } - extractExpressionAtPosition(pos: number): Promise { + async extractExpressionAtPosition(pos: number): Promise { return new Promise((resolve, reject) => { if (!this.parsedScript) { throw "PeekOverlayExpressionIdentifier - No valid script found"; @@ -77,7 +77,7 @@ export class PeekOverlayExpressionIdentifier { } } -export type PeekOverlayExpressionIdentifierOptions = { +export interface PeekOverlayExpressionIdentifierOptions { sourceType: SourceType; thisExpressionReplacement?: string; -}; +} diff --git a/app/client/packages/ast/src/utils.ts b/app/client/packages/ast/src/utils.ts index f6bc2e2aa7..6e595ebe8d 100644 --- a/app/client/packages/ast/src/utils.ts +++ b/app/client/packages/ast/src/utils.ts @@ -25,10 +25,10 @@ export const isTrueObject = ( export const getNameFromPropertyNode = (node: PropertyNode): string => isLiteralNode(node.key) ? String(node.key.value) : node.key.name; -type Position = { +interface Position { line: number; ch: number; -}; +} export const extractContentByPosition = ( content: string, @@ -58,3 +58,14 @@ export const extractContentByPosition = ( } return returnedString; }; + +export const getStringValue = ( + inputValue: string | number | boolean | RegExp, +) => { + if (typeof inputValue === "object" || typeof inputValue === "boolean") { + inputValue = JSON.stringify(inputValue); + } else if (typeof inputValue === "number" || typeof inputValue === "string") { + inputValue += ""; + } + return inputValue; +}; diff --git a/app/client/packages/design-system/headless/package.json b/app/client/packages/design-system/headless/package.json index e1db29e74b..454b03422e 100644 --- a/app/client/packages/design-system/headless/package.json +++ b/app/client/packages/design-system/headless/package.json @@ -14,17 +14,22 @@ "@react-aria/checkbox": "^3.9.0", "@react-aria/focus": "^3.11.0", "@react-aria/interactions": "^3.14.0", + "@react-aria/menu": "^3.11.1", "@react-aria/radio": "^3.6.1", "@react-aria/switch": "^3.5.2", + "@react-aria/textfield": "^3.11.0", "@react-aria/utils": "^3.16.0", "@react-aria/visually-hidden": "^3.8.0", "@react-spectrum/utils": "^3.9.0", "@react-stately/checkbox": "^3.4.1", + "@react-stately/collections": "^3.10.2", + "@react-stately/menu": "^3.5.6", "@react-stately/radio": "^3.8.1", "@react-stately/toggle": "^3.5.1", "@react-types/button": "^3.7.1", "@react-types/checkbox": "^3.4.3", "@react-types/label": "^3.7.3", + "@react-types/menu": "^3.9.5", "@react-types/shared": "^3.17.0", "classnames": "*" }, diff --git a/app/client/packages/design-system/headless/src/components/Button/index.ts b/app/client/packages/design-system/headless/src/components/Button/index.ts new file mode 100644 index 0000000000..3bd16e178a --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Button/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/headless/src/components/Button/Button.tsx b/app/client/packages/design-system/headless/src/components/Button/src/Button.tsx similarity index 89% rename from app/client/packages/design-system/headless/src/components/Button/Button.tsx rename to app/client/packages/design-system/headless/src/components/Button/src/Button.tsx index 5430dba777..9f4f8444cc 100644 --- a/app/client/packages/design-system/headless/src/components/Button/Button.tsx +++ b/app/client/packages/design-system/headless/src/components/Button/src/Button.tsx @@ -20,7 +20,13 @@ export type ButtonRef = React.Ref; type ButtonRefObject = React.RefObject; const _Button = (props: ButtonProps, ref: ButtonRef) => { - const { autoFocus, children, className, draggable, isDisabled } = props; + const { + autoFocus, + children, + className, + draggable = false, + isDisabled = false, + } = props; const { hoverProps, isHovered } = useHover({ isDisabled }); const { focusProps, isFocusVisible } = useFocusRing({ autoFocus }); const { buttonProps, isPressed } = useButton(props, ref as ButtonRefObject); @@ -28,8 +34,8 @@ const _Button = (props: ButtonProps, ref: ButtonRef) => { return ( + + Cut + Copy + Paste + + + ); +}; + +# Menu + +A menu displays a list of actions or options that a user can choose. + + + {Template.bind({})} + + +## Menu props + + + +## MenuList props + + + +## Item props + +Item props are not pulled up in the ArgsTable, the data can be found [here](https://react-spectrum.adobe.com/react-aria/Menu.html#item). + +# Placement + +The placement of the menu can be changed by passing the `placement` prop. + +# Placement + +The placement of the menu can be changed by passing the `placement` prop. + + + + + + Copy + Cut + Paste + + + + + + Copy + Cut + Paste + + + + + + Copy + Cut + Paste + + + + + + Copy + Cut + Paste + + + + +# Menu example + + + + console.log(key)} + > + + {(item) => {item.name}} + + + + + console.log(key)} +> + + {(item) => {item.name}} + +`} +/> diff --git a/app/client/packages/design-system/headless/src/components/Popover/index.ts b/app/client/packages/design-system/headless/src/components/Popover/index.ts new file mode 100644 index 0000000000..3bd16e178a --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Popover/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/headless/src/components/Popover/src/Popover.tsx b/app/client/packages/design-system/headless/src/components/Popover/src/Popover.tsx new file mode 100644 index 0000000000..50a33dc6a7 --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Popover/src/Popover.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import { usePopover } from "./usePopover"; +import { PopoverContext } from "./PopoverContext"; + +import type { PopoverProps } from "./types"; + +export const Popover = (props: PopoverProps) => { + const { children, modal = false, ...rest } = props; + const popover = usePopover({ modal, children, ...rest }); + + return ( + + {children} + + ); +}; diff --git a/app/client/packages/design-system/headless/src/components/Popover/src/PopoverContent.tsx b/app/client/packages/design-system/headless/src/components/Popover/src/PopoverContent.tsx new file mode 100644 index 0000000000..067d44efe9 --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Popover/src/PopoverContent.tsx @@ -0,0 +1,46 @@ +import React, { forwardRef } from "react"; +import { + FloatingFocusManager, + FloatingPortal, + useMergeRefs, +} from "@floating-ui/react"; +import { usePopoverContext } from "./PopoverContext"; + +import type { Ref } from "react"; +import type { PopoverContentProps } from "./types"; + +const _PopoverContent = (props: PopoverContentProps, ref: Ref) => { + const { children, className, closeOnFocusOut = true, style } = props; + const { context, descriptionId, getFloatingProps, labelId, modal, open } = + usePopoverContext(); + const refs = useMergeRefs([context.refs.setFloating, ref]); + + if (!Boolean(open)) return null; + + const root = context.refs.domReference.current?.closest( + "[data-theme-provider]", + ) as HTMLElement; + + return ( + + +
    + {children} +
    +
    +
    + ); +}; + +export const PopoverContent = forwardRef(_PopoverContent); diff --git a/app/client/packages/design-system/headless/src/components/Popover/src/PopoverContext.tsx b/app/client/packages/design-system/headless/src/components/Popover/src/PopoverContext.tsx new file mode 100644 index 0000000000..fa7a6ed8c7 --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Popover/src/PopoverContext.tsx @@ -0,0 +1,14 @@ +import React, { useContext } from "react"; +import type { ContextType } from "./types"; + +export const PopoverContext = React.createContext(null); + +export const usePopoverContext = () => { + const context = useContext(PopoverContext); + + if (context == null) { + throw new Error("Popover components must be wrapped in "); + } + + return context; +}; diff --git a/app/client/packages/design-system/headless/src/components/Popover/src/PopoverTrigger.tsx b/app/client/packages/design-system/headless/src/components/Popover/src/PopoverTrigger.tsx new file mode 100644 index 0000000000..095bc8a833 --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Popover/src/PopoverTrigger.tsx @@ -0,0 +1,46 @@ +import { isValidElement, forwardRef, cloneElement } from "react"; +import { useMergeRefs } from "@floating-ui/react"; +import { usePopoverContext } from "./PopoverContext"; + +import type { ButtonProps } from "../../Button"; +import type { AriaAttributes, Ref } from "react"; +import type { PopoverTriggerProps } from "./types"; + +const _PopoverTrigger = ( + props: PopoverTriggerProps, + propRef: Ref, +) => { + const { children } = props; + const context = usePopoverContext(); + // @ts-expect-error we don't know which type children will be + const childrenRef = (children as unknown).ref; + const ref = useMergeRefs([context.refs.setReference, propRef, childrenRef]); + + if (isValidElement(children)) { + const referenceProps = context.getReferenceProps({ + ref, + ...props, + }); + + return cloneElement(children, { + onPress: () => { + context.setOpen(!context.open); + }, + "aria-controls": referenceProps[ + "aria-controls" + ] as AriaAttributes["aria-controls"], + "aria-expanded": referenceProps[ + "aria-expanded" + ] as AriaAttributes["aria-expanded"], + "aria-haspopup": referenceProps[ + "aria-haspopup" + ] as AriaAttributes["aria-haspopup"], + ref, + ...children.props, + } as ButtonProps); + } + + throw new Error("PopoverTrigger children component must be + + Controlled popover content + + ); +}; diff --git a/app/client/packages/design-system/headless/src/components/Popover/stories/Popover.stories.mdx b/app/client/packages/design-system/headless/src/components/Popover/stories/Popover.stories.mdx new file mode 100644 index 0000000000..943ae86c56 --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Popover/stories/Popover.stories.mdx @@ -0,0 +1,101 @@ +import { + Popover, + PopoverTrigger, + PopoverContent, + Button, +} from "@design-system/headless"; +import { ControlledPopover } from "./ControlledPopover"; +import { Canvas, Meta, Story, ArgsTable, Source } from "@storybook/addon-docs"; + + + +export const Template = (args) => { + return ( + + + + + My popover + + ); +}; + +# Popover + +A popover is an interactive mini-dialog floating element that displays information related to an anchor element when the element is clicked. + +Based on the [headless Popover component](/?path=/docs/design-system-headless-popover--docs). + + + {Template.bind({})} + + +## Popover props + + + +## PopoverTrigger props + + + +## PopoverContent props + + + +# Placement + +The placement of the popover can be changed by passing the `placement` prop. + + + + + + + + My popover + + + + + + My popover + + + + + + My popover + + + + + + My popover + + + + +# Controlled popover + + + + + + + + { + const [isOpen, setIsOpen] = useState(false); + return ( + + + + + Controlled popover content + + ); +}; +`} +/> diff --git a/app/client/packages/design-system/headless/src/components/Radio/index.ts b/app/client/packages/design-system/headless/src/components/Radio/index.ts new file mode 100644 index 0000000000..3bd16e178a --- /dev/null +++ b/app/client/packages/design-system/headless/src/components/Radio/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/headless/src/components/Radio/Radio.tsx b/app/client/packages/design-system/headless/src/components/Radio/src/Radio.tsx similarity index 92% rename from app/client/packages/design-system/headless/src/components/Radio/Radio.tsx rename to app/client/packages/design-system/headless/src/components/Radio/src/Radio.tsx index b69f4708f9..67e8a37e22 100644 --- a/app/client/packages/design-system/headless/src/components/Radio/Radio.tsx +++ b/app/client/packages/design-system/headless/src/components/Radio/src/Radio.tsx @@ -10,7 +10,7 @@ import type { FocusableRef, StyleProps } from "@react-types/shared"; import { RadioContext } from "./context"; import type { RadioGroupContext } from "./context"; -import type { InlineLabelProps } from "../Checkbox"; +import type { InlineLabelProps } from "../../Checkbox"; export interface RadioProps extends Omit, @@ -26,6 +26,7 @@ const _Radio = (props: RadioProps, ref: RadioRef) => { children, className, isDisabled: isDisabledProp = false, + labelPosition = "right", } = props; const inputRef = useRef(null); const domRef = useFocusableRef(ref, inputRef); @@ -49,11 +50,12 @@ const _Radio = (props: RadioProps, ref: RadioRef) => {