├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .prettierrc ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── cypress.json ├── cypress ├── fixtures │ ├── example.json │ └── prevaluesource.txt ├── integration │ ├── Content │ │ ├── content.ts │ │ ├── routing.ts │ │ └── urlpicker.ts │ ├── DataTypes │ │ └── dataTypes.ts │ ├── Forms │ │ ├── dataSourceTest.ts │ │ ├── formTest.ts │ │ └── prevaluesourcesTest.ts │ ├── HelpPanel │ │ └── systemInformation.ts │ ├── Login │ │ └── login.ts │ ├── Media │ │ └── media.ts │ ├── Members │ │ ├── memberGroups.js │ │ └── members.js │ ├── Packages │ │ └── packages.ts │ ├── Settings │ │ ├── dataTypes.ts │ │ ├── documentTypes.ts │ │ ├── languages.ts │ │ ├── macros.ts │ │ ├── mediaTypes.ts │ │ ├── memberTypes.ts │ │ ├── partialsViewMacroFiles.ts │ │ ├── partialsViews.ts │ │ ├── relationTypes.ts │ │ ├── scripts.ts │ │ ├── stylesheets.ts │ │ └── templates.ts │ ├── Tabs │ │ └── tabs.ts │ ├── Tour │ │ └── backofficeTour.ts │ └── Users │ │ ├── userGroups.ts │ │ └── users.ts ├── plugins │ └── index.js ├── support │ └── index.js ├── tsconfig.json └── typings.d.ts ├── jest.config.js ├── package.json ├── postinstall.js ├── src ├── cms │ ├── builders │ │ ├── content │ │ │ ├── contentBuilder.ts │ │ │ ├── contentVariantBuilder.ts │ │ │ ├── contentVariantPropertyBuilder.ts │ │ │ └── index.ts │ │ ├── dataTypes │ │ │ ├── approvedColorPickerTypeDataTypeBuilder.ts │ │ │ ├── checkBoxListDataTypeBuilder.ts │ │ │ ├── dataTypeBuilder.ts │ │ │ ├── dropDownDataTypeBuilder.ts │ │ │ ├── formPickerDataTypeBuilder.ts │ │ │ ├── gridBuilders │ │ │ │ ├── gridAreaBuilder.ts │ │ │ │ ├── gridLayoutBuilder.ts │ │ │ │ ├── gridRowConfigBuilder.ts │ │ │ │ ├── gridRteBuilder.ts │ │ │ │ ├── gridSettingsBuilder.ts │ │ │ │ ├── gridStylesBuilder.ts │ │ │ │ ├── index.ts │ │ │ │ ├── rteToolbarOptionsBuilder.ts │ │ │ │ └── sectionBuilder.ts │ │ │ ├── gridDataTypeBuilder.ts │ │ │ ├── index.ts │ │ │ ├── labelDataTypeBuilder.ts │ │ │ └── textBoxDataTypeBuilder.ts │ │ ├── documentTypes │ │ │ ├── documentTypeBuilder.ts │ │ │ ├── documentTypeGroupBuilder.ts │ │ │ ├── documentTypeTabBuilder.ts │ │ │ ├── index.ts │ │ │ └── properties │ │ │ │ ├── approvedColorPickerTypeDataTypeBuilder.ts │ │ │ │ ├── contentPickerTypePropertyBuilder.ts │ │ │ │ ├── customDocumentTypePropertyBuilder.ts │ │ │ │ ├── documentTypePropertyBuilder.ts │ │ │ │ ├── dropDownDocumentTypePropertyBuilder.ts │ │ │ │ ├── formPickerDocumentTypePropertyBuilder.ts │ │ │ │ ├── index.ts │ │ │ │ ├── richTextDocumentTypePropertyBuilder.ts │ │ │ │ ├── textBoxDocumentTypePropertyBuilder.ts │ │ │ │ └── urlPickerTypePropertyBuilder.ts │ │ ├── index.ts │ │ ├── macroBuilder.ts │ │ ├── media │ │ │ ├── index.ts │ │ │ ├── mediaBuilder.ts │ │ │ └── mediaPropertyBuilder.ts │ │ ├── partialViewMacros │ │ │ └── partialViewMacroBuilder.ts │ │ ├── partialViews │ │ │ └── partialViewBuilder.ts │ │ ├── scriptbuilder.ts │ │ ├── stylesheetBuilder.ts │ │ ├── templates │ │ │ ├── index.ts │ │ │ └── templateBuilder.ts │ │ ├── user │ │ │ ├── index.ts │ │ │ └── userBuilder.ts │ │ └── userGroups │ │ │ ├── index.ts │ │ │ ├── nodePermissionBuilder.ts │ │ │ ├── nodePermissionCollectionBuilder.ts │ │ │ ├── permissionsBuilder.ts │ │ │ └── userGroupBuilder.ts │ ├── models │ │ ├── cmsDocumentType.ts │ │ ├── dataTypes │ │ │ ├── approvedColourPickerDataType.ts │ │ │ ├── checkBoxListDataType.ts │ │ │ ├── dataType.ts │ │ │ ├── dataTypePrevalue.ts │ │ │ ├── dropDownDataType.ts │ │ │ ├── formPickerDataType.ts │ │ │ ├── gridDataType.ts │ │ │ ├── index.ts │ │ │ ├── labelDataType.ts │ │ │ └── textBoxDataType.ts │ │ ├── index.ts │ │ ├── partialViewMacros │ │ │ └── partialViewMacro.ts │ │ ├── properties │ │ │ ├── baseProperty.ts │ │ │ ├── dropDownProperty.ts │ │ │ ├── formPickerProperty.ts │ │ │ ├── index.ts │ │ │ └── textBoxProperty.ts │ │ └── template.ts │ └── templates │ │ ├── formPickerTemplate.ts │ │ ├── index.ts │ │ └── minimalTemplate.ts ├── cypress │ └── commands │ │ ├── chainable.ts │ │ ├── command.ts │ │ ├── commandBase.ts │ │ ├── cycleHackWorkaroundForPureLiveIssue.ts │ │ ├── dataUmb.ts │ │ ├── dataUmbScope.ts │ │ ├── deleteAllContent.ts │ │ ├── deleteAllDataSources.ts │ │ ├── deleteAllForms.ts │ │ ├── deleteAllPreValues.ts │ │ ├── deleteContentById.ts │ │ ├── deleteDataSourceByGuid.ts │ │ ├── deleteDataTypeById.ts │ │ ├── deleteDataTypesByNamePrefix.ts │ │ ├── deleteDocumentType.ts │ │ ├── deleteDocumentTypeById.ts │ │ ├── deleteDocumentTypesByNamePrefix.ts │ │ ├── deleteForm.ts │ │ ├── deleteFormByGuid.ts │ │ ├── deleteFormsByNamePrefix.ts │ │ ├── deletePreValueSourceByGuid.ts │ │ ├── deleteTemplateById.ts │ │ ├── deleteTemplatesByNamePrefix.ts │ │ ├── editTemplate.ts │ │ ├── getAngular.ts │ │ ├── postFile.ts │ │ ├── postRequest.ts │ │ ├── saveCodeFile.ts │ │ ├── saveContent.ts │ │ ├── saveDataType.ts │ │ ├── saveDocumentType.ts │ │ ├── saveFolder.ts │ │ ├── saveForm.ts │ │ ├── saveMacro.ts │ │ ├── saveMacroWithPartial.ts │ │ ├── saveMedia.ts │ │ ├── savePartialView.ts │ │ ├── savePartialViewMacro.ts │ │ ├── saveScript.ts │ │ ├── saveStylesheet.ts │ │ ├── saveTemplate.ts │ │ ├── saveUser.ts │ │ ├── saveUserGroup.ts │ │ ├── umbracoApiRequest.ts │ │ ├── umbracoButtonByLabelKey.ts │ │ ├── umbracoContextMenuAction.ts │ │ ├── umbracoCreateDocTypeWithContent.ts │ │ ├── umbracoEditorHeaderName.ts │ │ ├── umbracoEnsureDataTypeNameNotExists.ts │ │ ├── umbracoEnsureDocumentTypeNameNotExists.ts │ │ ├── umbracoEnsureLanguageNameNotExists.ts │ │ ├── umbracoEnsureMacroNameNotExists.ts │ │ ├── umbracoEnsureMediaNameNotExists.ts │ │ ├── umbracoEnsureMediaTypeNameNotExists.ts │ │ ├── umbracoEnsureMemberEmailNotExists.ts │ │ ├── umbracoEnsureMemberGroupNameNotExists.ts │ │ ├── umbracoEnsureMemberTypeNameNotExists.ts │ │ ├── umbracoEnsureMultipleDocumentTypeNameNotExists.ts │ │ ├── umbracoEnsurePackageNameNotExists.ts │ │ ├── umbracoEnsurePartialViewMacroFileNameNotExists.ts │ │ ├── umbracoEnsurePartialViewNameNotExists.ts │ │ ├── umbracoEnsureRelationTypeNameNotExists.ts │ │ ├── umbracoEnsureScriptNameNotExists.ts │ │ ├── umbracoEnsureStylesheetNameNotExists.ts │ │ ├── umbracoEnsureTemplateNameNotExists.ts │ │ ├── umbracoEnsureUserEmailNotExists.ts │ │ ├── umbracoEnsureUserGroupNameNotExists.ts │ │ ├── umbracoErrorNotification.ts │ │ ├── umbracoFileExists.ts │ │ ├── umbracoGlobalHelp.ts │ │ ├── umbracoGlobalUser.ts │ │ ├── umbracoInstall.ts │ │ ├── umbracoLogin.ts │ │ ├── umbracoMacroExists.ts │ │ ├── umbracoPartialViewExists.ts │ │ ├── umbracoRefreshContentTree.ts │ │ ├── umbracoScriptExists.ts │ │ ├── umbracoSection.ts │ │ ├── umbracoSetCurrentUserLanguage.ts │ │ ├── umbracoStylesheetExists.ts │ │ ├── umbracoSuccessNotification.ts │ │ ├── umbracoTreeItem.ts │ │ ├── umbracoVerifyRenderedViewContent.ts │ │ ├── umbracoVerifyScriptContent.ts │ │ └── umbracoVerifyStylesheetContent.ts ├── forms │ ├── builders │ │ ├── fields │ │ │ ├── conditions │ │ │ │ ├── formFieldConditionBuilder.ts │ │ │ │ ├── formFieldConditionRuleBuilder.ts │ │ │ │ └── index.ts │ │ │ ├── dropDownFieldBuilder.ts │ │ │ ├── fileUploadFieldBuilder.ts │ │ │ ├── formCheckboxFieldBuilder.ts │ │ │ ├── formDateFieldBuilder.ts │ │ │ ├── formFieldBuilderBase.ts │ │ │ ├── formLongAnswerFieldBuilder.ts │ │ │ ├── formPasswordFieldBuilder.ts │ │ │ ├── formShortAnswerFieldBuilder.ts │ │ │ └── index.ts │ │ ├── formBuilder.ts │ │ ├── formContainerBuilder.ts │ │ ├── formFieldSetBuilder.ts │ │ ├── formPageBuilder.ts │ │ ├── helpers │ │ │ ├── contentBuilderHelper.ts │ │ │ ├── dataSourcesBuilderHelper.ts │ │ │ ├── dataTypesBuilderHelper.ts │ │ │ ├── documentTypeBuilderHelper.ts │ │ │ ├── formBuilderHelper.ts │ │ │ ├── index.ts │ │ │ ├── prevalueSourcesBuilderHelper.ts │ │ │ ├── propertyBuilderHelper.ts │ │ │ └── templateBuilderHelper.ts │ │ ├── iBuilder.ts │ │ ├── index.ts │ │ └── workflows │ │ │ ├── formWorkflowBuilder.ts │ │ │ ├── index.ts │ │ │ └── workflowTypeSetting.ts │ ├── models │ │ ├── checkboxField.ts │ │ ├── dateField.ts │ │ ├── dropDownField.ts │ │ ├── fileUploadField.ts │ │ ├── formField.ts │ │ ├── formModel.ts │ │ ├── index.ts │ │ ├── longAnswerField.ts │ │ ├── passwordField.ts │ │ ├── saveAsUmbracoContentNodeWorkflowModel.ts │ │ ├── sendEmailRazorModel.ts │ │ ├── shortAnswerField.ts │ │ ├── workflow.ts │ │ └── workflowSettings.ts │ └── workflows │ │ ├── changeRecordStateWorkflow.ts │ │ ├── index.ts │ │ ├── postAsXMLWorkflow.ts │ │ ├── saveAsAnXMLFileWorkflow.ts │ │ ├── saveAsUmbracoContentNodeWorkflow.ts │ │ ├── sendEmailRazorWorkflow.ts │ │ ├── sendEmailWorkflow.ts │ │ ├── sendFormToUrl.ts │ │ └── sendXsltTransformedEmail.ts ├── helpers │ ├── aliasHelper.ts │ ├── jsonHelper.ts │ └── responseHelper.ts └── index.ts ├── tests ├── builders │ ├── contentBuilder.spec.ts │ ├── dataTypeBuilder.spec.ts │ ├── documentTypeBuilder.spec.ts │ └── formBuilder.spec.ts ├── cypress │ ├── commands │ │ ├── commandBase.spec.ts │ │ └── umbracoLogin.spec.ts │ └── testDoubles │ │ ├── cyTestDouble.ts │ │ └── cypressTestDouble.ts └── tsconfig.json └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@typescript-eslint/recommended"], 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 2020, // Allows for the parsing of modern ECMAScript features 6 | "sourceType": "module" 7 | }, 8 | "rules": { 9 | "@typescript-eslint/ban-ts-comment" : "warn" 10 | } 11 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Compiled binary addons (http://nodejs.org/api/addons.html) 21 | build/Release 22 | 23 | # Dependency directories 24 | node_modules 25 | jspm_packages 26 | 27 | # Optional npm cache directory 28 | .npm 29 | 30 | # Optional REPL history 31 | .node_repl_history 32 | 33 | # Editors 34 | .idea 35 | .vs 36 | 37 | # Lib 38 | lib 39 | 40 | # npm package lock 41 | package-lock.json 42 | yarn.lock 43 | 44 | others 45 | .DS_Store 46 | /test-results.xml 47 | /cypress/screenshots/ 48 | /cypress/videos/ 49 | *.tgz 50 | test-results.trx 51 | /coverage 52 | *.trx -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.log 2 | npm-debug.log* 3 | 4 | # Editors 5 | .idea 6 | .vs 7 | 8 | # Coverage directory used by tools like istanbul 9 | coverage 10 | .nyc_output 11 | 12 | # Dependency directories 13 | node_modules 14 | 15 | # npm package lock 16 | package-lock.json 17 | yarn.lock 18 | 19 | # project files 20 | src 21 | test 22 | CHANGELOG.md, 23 | test-results.xml 24 | .editorconfig 25 | .eslintignore 26 | .eslintrc 27 | .babelrc 28 | .gitignore 29 | 30 | 31 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "trailingComma": "all", 4 | "singleQuote": true 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-present Bjarke Berg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Node.js 2 | # Build a general Node.js project with npm. 3 | # Add steps that analyze code, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'ubuntu-latest' 11 | 12 | steps: 13 | - task: NodeTool@0 14 | inputs: 15 | versionSpec: '10.x' 16 | displayName: 'Install Node.js' 17 | 18 | - script: | 19 | npm install 20 | displayName: 'Prepare' 21 | 22 | - task: PublishTestResults@2 23 | displayName: "Publish test results" 24 | inputs: 25 | testResultsFormat: 'VSTest' 26 | testResultsFiles: 'test-results.trx' 27 | 28 | - task: PublishCodeCoverageResults@1 29 | displayName: "Publish code coverage" 30 | inputs: 31 | codeCoverageTool: 'Cobertura' 32 | summaryFileLocation: 'coverage/cobertura-coverage.xml' 33 | reportDirectory: 'coverage' 34 | 35 | - script: | 36 | npm run pack 37 | displayName: 'Prepare and generate package' 38 | 39 | - task: CopyFiles@2 40 | displayName: 'Copy files to artifacts' 41 | inputs: 42 | Contents: | 43 | **/* 44 | !.git/**/* 45 | !node_modules/**/* 46 | TargetFolder: '$(build.artifactstagingdirectory)' 47 | 48 | - task: PublishBuildArtifacts@1 49 | displayName: 'Publish artifacts' 50 | inputs: 51 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 52 | ArtifactName: 'Content' 53 | publishLocation: 'Container' 54 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "https://localhost:44331", 3 | "viewportHeight": 1024, 4 | "viewportWidth": 1200, 5 | "env": { 6 | "username": "bmb@umbraco.dk", 7 | "password": "1234567890" 8 | }, 9 | "ignoreTestFiles": ["**/Forms/*.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/fixtures/prevaluesource.txt: -------------------------------------------------------------------------------- 1 | Prevalue1 2 | Prevalue2 3 | Prevalue3 4 | Prevalue4 5 | Prevalue5 -------------------------------------------------------------------------------- /cypress/integration/HelpPanel/systemInformation.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | function openSystemInformation(){ 4 | //We have to wait for page to load, if the site is slow 5 | cy.get('[data-element="global-help"]').should('be.visible', {timeout:10000}).click(); 6 | cy.get('.umb-help-list-item').last().should('be.visible').click(); 7 | cy.get('.umb-drawer-content').scrollTo('bottom', {ensureScrollable : false}); 8 | } 9 | 10 | context('System Information', () => { 11 | 12 | beforeEach(() => { 13 | //arrange 14 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 15 | cy.umbracoSetCurrentUserLanguage('en-US'); 16 | }); 17 | 18 | it('Check System Info Displays', () => { 19 | openSystemInformation(); 20 | cy.get('.table').find('tr').should('have.length', 10); 21 | cy.contains('Current Culture').parent().should('contain', 'en-US'); 22 | cy.contains('Current UI Culture').parent().should('contain', 'en-US'); 23 | }); 24 | 25 | it('Checks language displays correctly after switching', () => { 26 | 27 | //Navigate to edit user and change language 28 | cy.get('[data-element="global-user"]').click(); 29 | cy.get('[alias="editUser"]').click(); 30 | cy.get('[name="culture"]').select('string:da-DK', {timeout: 10000, force: true}); 31 | cy.umbracoButtonByLabelKey('buttons_save').click({force: true}); 32 | //Refresh site to display new language 33 | cy.reload(); 34 | openSystemInformation(); 35 | //Assert 36 | cy.contains('Current Culture').parent().should('contain', 'da-DK'); 37 | cy.contains('Current UI Culture').parent().should('contain', 'da-DK'); 38 | cy.get('.umb-button__content').last().click(); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /cypress/integration/Login/login.ts: -------------------------------------------------------------------------------- 1 | /// 2 | context('Login', () => { 3 | 4 | beforeEach(() => { 5 | cy.visit('/umbraco'); 6 | }); 7 | 8 | it('Login with correct username and password', () => { 9 | const username = Cypress.env('username'); 10 | const password = Cypress.env('password'); 11 | //Precondition 12 | cy.get('.text-error').should('not.exist'); 13 | 14 | //Action 15 | cy.get('#umb-username').type(username); 16 | cy.get('#umb-passwordTwo').type(password); 17 | cy.get('[label-key="general_login"]').click(); 18 | 19 | //Assert 20 | cy.url().should('include', '/umbraco#/content') 21 | cy.get('#umb-username').should('not.exist'); 22 | cy.get('#umb-passwordTwo').should('not.exist'); 23 | }); 24 | 25 | 26 | it('Login with correct username but wrong password', () => { 27 | const username = Cypress.env('username'); 28 | const password = 'wrong'; 29 | 30 | //Precondition 31 | cy.get('.text-error').should('not.exist'); 32 | 33 | //Action 34 | cy.get('#umb-username').type(username); 35 | cy.get('#umb-passwordTwo').type(password); 36 | cy.get('[label-key="general_login"]').click(); 37 | 38 | //Assert 39 | cy.get('.text-error').should('exist'); 40 | cy.get('#umb-username').should('exist'); 41 | cy.get('#umb-passwordTwo').should('exist'); 42 | }); 43 | 44 | it('Login with wrong username and wrong password', () => { 45 | const username = 'wrong-username'; 46 | const password = 'wrong'; 47 | 48 | //Precondition 49 | cy.get('.text-error').should('not.exist'); 50 | 51 | //Action 52 | cy.get('#umb-username').type(username); 53 | cy.get('#umb-passwordTwo').type(password); 54 | cy.get('[label-key="general_login"]').click(); 55 | 56 | //Assert 57 | cy.get('.text-error').should('exist'); 58 | cy.get('#umb-username').should('exist'); 59 | cy.get('#umb-passwordTwo').should('exist'); 60 | }); 61 | 62 | }); -------------------------------------------------------------------------------- /cypress/integration/Members/memberGroups.js: -------------------------------------------------------------------------------- 1 | context('User Groups', () => { 2 | 3 | beforeEach(() => { 4 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 5 | }); 6 | 7 | it('Create member group', () => { 8 | const name = "Test Group"; 9 | 10 | cy.umbracoEnsureMemberGroupNameNotExists(name); 11 | 12 | cy.umbracoSection('member'); 13 | cy.get('li .umb-tree-root:contains("Members")').should("be.visible"); 14 | 15 | cy.umbracoTreeItem("member", ["Member Groups"]).rightclick(); 16 | 17 | cy.umbracoContextMenuAction("action-create").click(); 18 | 19 | //Type name 20 | cy.umbracoEditorHeaderName(name); 21 | 22 | // Save 23 | cy.get('.btn-success').click(); 24 | 25 | //Assert 26 | cy.umbracoSuccessNotification().should('be.visible'); 27 | 28 | //Clean up 29 | cy.umbracoEnsureMemberGroupNameNotExists(name); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /cypress/integration/Members/members.js: -------------------------------------------------------------------------------- 1 | /// 2 | context('Members', () => { 3 | 4 | beforeEach(() => { 5 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 6 | }); 7 | 8 | it('Create member', () => { 9 | const name = "Alice Bobson"; 10 | const email = "alice-bobson@acceptancetest.umbraco"; 11 | const password = "$AUlkoF*St0kgPiyyVEk5iU5JWdN*F7&"; 12 | const passwordTimeout = 20000 13 | 14 | cy.umbracoEnsureMemberEmailNotExists(email); 15 | cy.umbracoSection('member'); 16 | cy.get('li .umb-tree-root:contains("Members")').should("be.visible"); 17 | 18 | cy.umbracoTreeItem("member", ["Members"]).rightclick(); 19 | 20 | cy.umbracoContextMenuAction("action-create").click(); 21 | cy.get('.menu-label').first().click(); 22 | 23 | //Type name 24 | cy.umbracoEditorHeaderName(name); 25 | 26 | cy.get('input#_umb_login').clear().type(email); 27 | cy.get('input#_umb_email').clear().type(email); 28 | cy.get('input#password').clear().type(password, { timeout: passwordTimeout }); 29 | cy.get('input#confirmPassword').clear().type(password, { timeout: passwordTimeout }); 30 | 31 | // Save 32 | cy.get('.btn-success').click(); 33 | 34 | //Assert 35 | cy.umbracoSuccessNotification().should('be.visible'); 36 | 37 | //Clean up 38 | cy.umbracoEnsureMemberEmailNotExists(email); 39 | 40 | }); 41 | 42 | }); 43 | -------------------------------------------------------------------------------- /cypress/integration/Settings/dataTypes.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import {LabelDataTypeBuilder} from "../../../src"; 3 | context('Data Types', () => { 4 | 5 | beforeEach(() => { 6 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 7 | }); 8 | 9 | it('Create data type', () => { 10 | const name = "Test data type"; 11 | 12 | cy.umbracoEnsureDataTypeNameNotExists(name); 13 | 14 | cy.umbracoSection('settings'); 15 | cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); 16 | 17 | cy.umbracoTreeItem("settings", ["Data Types"]).rightclick(); 18 | 19 | cy.umbracoContextMenuAction("action-create").click(); 20 | cy.umbracoContextMenuAction("action-data-type").click(); 21 | 22 | //Type name 23 | cy.umbracoEditorHeaderName(name); 24 | 25 | 26 | cy.get('select[name="selectedEditor"]').select('Label'); 27 | 28 | cy.get('.umb-property-editor select').select('Time'); 29 | 30 | //Save 31 | cy.get('.btn-success').click(); 32 | 33 | //Assert 34 | cy.umbracoSuccessNotification().should('be.visible'); 35 | 36 | //Clean up 37 | cy.umbracoEnsureDataTypeNameNotExists(name); 38 | }); 39 | 40 | it('Delete data type', () => { 41 | const name = "Test data type"; 42 | cy.umbracoEnsureDataTypeNameNotExists(name); 43 | 44 | const dataType = new LabelDataTypeBuilder() 45 | .withSaveNewAction() 46 | .withName(name) 47 | .build(); 48 | 49 | cy.saveDataType(dataType); 50 | 51 | cy.umbracoSection('settings'); 52 | cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); 53 | 54 | cy.umbracoTreeItem("settings", ["Data Types", name]).rightclick(); 55 | 56 | cy.umbracoContextMenuAction("action-delete").click(); 57 | 58 | cy.umbracoButtonByLabelKey("general_delete").click(); 59 | 60 | cy.contains(name).should('not.exist'); 61 | 62 | cy.umbracoEnsureDataTypeNameNotExists(name); 63 | 64 | 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /cypress/integration/Settings/languages.ts: -------------------------------------------------------------------------------- 1 | /// 2 | context('Languages', () => { 3 | 4 | beforeEach(() => { 5 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 6 | }); 7 | 8 | it('Add language', () => { 9 | const name = "Kyrgyz (Kyrgyzstan)"; // Must be an option in the select box 10 | 11 | cy.umbracoEnsureLanguageNameNotExists(name); 12 | 13 | cy.umbracoSection('settings'); 14 | cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); 15 | 16 | cy.umbracoTreeItem("settings", ["Languages"]).click(); 17 | 18 | cy.umbracoButtonByLabelKey("languages_addLanguage").click(); 19 | 20 | cy.get('select[name="newLang"]').select(name); 21 | 22 | // //Save 23 | cy.get('.btn-success').click(); 24 | 25 | //Assert 26 | cy.umbracoSuccessNotification().should('be.visible'); 27 | 28 | //Clean up 29 | cy.umbracoEnsureLanguageNameNotExists(name); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /cypress/integration/Settings/macros.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { PartialViewMacroBuilder, MacroBuilder, DocumentTypeBuilder, ContentBuilder, AliasHelper, GridDataTypeBuilder } from '../../../src'; 3 | 4 | context('Macros', () => { 5 | 6 | beforeEach(() => { 7 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 8 | }); 9 | 10 | function refreshContentTree(){ 11 | // Refresh to update the tree 12 | cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); 13 | cy.umbracoContextMenuAction("action-refreshNode").click(); 14 | // We have to wait in case the execution is slow, otherwise we'll try and click the item before it appears in the UI 15 | cy.get('.umb-tree-item__inner').should('exist', {timeout: 10000}); 16 | } 17 | 18 | it('Create macro', () => { 19 | const name = "Test macro"; 20 | 21 | cy.umbracoEnsureMacroNameNotExists(name); 22 | 23 | cy.umbracoSection('settings'); 24 | cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); 25 | 26 | cy.umbracoTreeItem("settings", ["Macros"]).rightclick(); 27 | 28 | cy.umbracoContextMenuAction("action-create").click(); 29 | 30 | cy.get('form[name="createMacroForm"]').within(($form) => { 31 | cy.get('input[name="itemKey"]').type(name); 32 | cy.get(".btn-primary").click(); 33 | }); 34 | 35 | cy.location().should((loc) => { 36 | expect(loc.hash).to.include('#/settings/macros/edit/') 37 | }); 38 | 39 | //Clean up 40 | cy.umbracoEnsureMacroNameNotExists(name); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /cypress/integration/Settings/mediaTypes.ts: -------------------------------------------------------------------------------- 1 | /// 2 | context('Media Types', () => { 3 | 4 | beforeEach(() => { 5 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 6 | }); 7 | 8 | it('Create media type', () => { 9 | const name = "Test media type"; 10 | 11 | cy.umbracoEnsureMediaTypeNameNotExists(name); 12 | 13 | cy.umbracoSection('settings'); 14 | cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); 15 | 16 | cy.umbracoTreeItem("settings", ["Media Types"]).rightclick(); 17 | 18 | cy.umbracoContextMenuAction("action-create").click(); 19 | cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-mediaType").click(); 20 | 21 | 22 | //Type name 23 | cy.umbracoEditorHeaderName(name); 24 | 25 | 26 | cy.get('[data-element="group-add"]').click(); 27 | 28 | cy.get('.umb-group-builder__group-title-input').type('Group name'); 29 | cy.get('[data-element="property-add"]').click(); 30 | cy.get('.editor-label').type('property name'); 31 | cy.get('[data-element="editor-add"]').click(); 32 | 33 | //Search for textstring 34 | cy.get('#datatype-search').type('Textstring'); 35 | 36 | // Choose first item 37 | cy.get('ul.umb-card-grid li [title="Textstring"]').closest("li").click(); 38 | 39 | // Save property 40 | cy.get('.btn-success').last().click(); 41 | 42 | //Save 43 | cy.get('.btn-success').click(); 44 | 45 | //Assert 46 | cy.umbracoSuccessNotification().should('be.visible'); 47 | 48 | //Clean up 49 | cy.umbracoEnsureMediaTypeNameNotExists(name); 50 | }); 51 | 52 | }); 53 | -------------------------------------------------------------------------------- /cypress/integration/Settings/memberTypes.ts: -------------------------------------------------------------------------------- 1 | /// 2 | context('Member Types', () => { 3 | 4 | beforeEach(() => { 5 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 6 | }); 7 | 8 | it('Create member type', () => { 9 | const name = "Test member type"; 10 | 11 | cy.umbracoEnsureMemberTypeNameNotExists(name); 12 | 13 | cy.umbracoSection('settings'); 14 | cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); 15 | 16 | cy.umbracoTreeItem("settings", ["Member Types"]).rightclick(); 17 | 18 | cy.umbracoContextMenuAction("action-create").click(); 19 | 20 | //Type name 21 | cy.umbracoEditorHeaderName(name); 22 | 23 | 24 | cy.get('[data-element="group-add"]').click(); 25 | 26 | cy.get('.umb-group-builder__group-title-input').type('Group name'); 27 | cy.get('[data-element="property-add"]').click(); 28 | cy.get('.editor-label').type('property name'); 29 | cy.get('[data-element="editor-add"]').click(); 30 | 31 | //Search for textstring 32 | cy.get('#datatype-search').type('Textstring'); 33 | 34 | // Choose first item 35 | cy.get('ul.umb-card-grid li [title="Textstring"]').closest("li").click(); 36 | 37 | // Save property 38 | cy.get('.btn-success').last().click(); 39 | 40 | //Save 41 | cy.get('.btn-success').click(); 42 | 43 | //Assert 44 | cy.umbracoSuccessNotification().should('be.visible'); 45 | 46 | //Clean up 47 | cy.umbracoEnsureMemberTypeNameNotExists(name); 48 | }); 49 | 50 | }); 51 | -------------------------------------------------------------------------------- /cypress/integration/Settings/relationTypes.ts: -------------------------------------------------------------------------------- 1 | /// 2 | context('Relation Types', () => { 3 | 4 | beforeEach(() => { 5 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 6 | }); 7 | 8 | it('Create relation type', () => { 9 | const name = "Test relation type"; 10 | 11 | cy.umbracoEnsureRelationTypeNameNotExists(name); 12 | 13 | cy.umbracoSection('settings'); 14 | cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); 15 | 16 | cy.umbracoTreeItem("settings", ["Relation Types"]).rightclick(); 17 | 18 | cy.umbracoContextMenuAction("action-create").click(); 19 | 20 | cy.get('form[name="createRelationTypeForm"]').within(($form) => { 21 | cy.get('input[name="relationTypeName"]').type(name); 22 | 23 | cy.get('[name="relationType-direction"] input').first().click({force:true}); 24 | 25 | cy.get('select[name="relationType-parent"]').select('Document'); 26 | 27 | cy.get('select[name="relationType-child"]').select('Media'); 28 | 29 | cy.get(".btn-primary").click(); 30 | }); 31 | 32 | cy.location().should((loc) => { 33 | expect(loc.hash).to.include('#/settings/relationTypes/edit/') 34 | }) 35 | 36 | //Clean up 37 | cy.umbracoEnsureRelationTypeNameNotExists(name); 38 | }); 39 | 40 | }); 41 | -------------------------------------------------------------------------------- /cypress/integration/Users/users.ts: -------------------------------------------------------------------------------- 1 | /// 2 | context('Users', () => { 3 | 4 | beforeEach(() => { 5 | cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); 6 | }); 7 | 8 | it('Create user', () => { 9 | const name = "Alice Bobson"; 10 | const email = "alice-bobson@acceptancetest.umbraco"; 11 | 12 | cy.umbracoEnsureUserEmailNotExists(email); 13 | cy.umbracoSection('users'); 14 | cy.umbracoButtonByLabelKey("user_createUser").click(); 15 | 16 | 17 | cy.get('input[name="name"]').type(name); 18 | cy.get('input[name="email"]').type(email); 19 | 20 | cy.get('.umb-node-preview-add').click(); 21 | cy.get('.umb-user-group-picker-list-item:nth-child(1) > .umb-user-group-picker__action').click(); 22 | cy.get('.umb-user-group-picker-list-item:nth-child(2) > .umb-user-group-picker__action').click(); 23 | cy.get('.btn-success').click(); 24 | 25 | cy.get('.umb-button > .btn > .umb-button__content').click(); 26 | 27 | 28 | cy.umbracoButtonByLabelKey("user_goToProfile").should('be.visible'); 29 | 30 | //Clean up 31 | cy.umbracoEnsureUserEmailNotExists(email); 32 | 33 | }); 34 | 35 | }); 36 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (on, config) => { 2 | on('before:browser:launch', (browser, launchOptions) => { 3 | if (browser.name === 'chrome' && browser.isHeadless) { 4 | launchOptions.args.push('--window-size=1400,1200') 5 | 6 | return launchOptions 7 | } 8 | }); 9 | on('task', { 10 | isFileExist 11 | }); 12 | } 13 | 14 | 15 | const { isFileExist } = require('cy-verify-downloads'); 16 | 17 | module.exports = (on, config) => { 18 | on('task', { isFileExist }) 19 | } -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import {Command} from '../../src/cypress/commands/command'; 18 | import {Chainable} from '../../src/cypress/commands/chainable'; 19 | require('cy-verify-downloads').addCustomCommand(); 20 | 21 | new Chainable(); 22 | new Command().registerCypressCommands(); 23 | import 'cypress-file-upload'; -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "types":[ 4 | "cypress" 5 | ], 6 | "include": [ 7 | "**/*.ts", 8 | "../src/cypress/commands/**/*.ts" 9 | ] 10 | 11 | } -------------------------------------------------------------------------------- /cypress/typings.d.ts: -------------------------------------------------------------------------------- 1 | // type definitions for Cypress object "cy" 2 | /// 3 | 4 | // type definitions for custom commands like "createDefaultTodos" 5 | // -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | "reporters": ["default", 5 | [ 6 | "jest-trx-results-processor", 7 | { 8 | "outputFile": "test-results.trx" 9 | } 10 | ] 11 | ] 12 | }; -------------------------------------------------------------------------------- /postinstall.js: -------------------------------------------------------------------------------- 1 | const ncp=require('ncp').ncp; 2 | const fs = require('fs'); 3 | const path= require('path'); 4 | 5 | const basepath = __dirname; 6 | const src = path.join(basepath,'src','cypress','commands','chainable.ts'); 7 | const dst = path.join(basepath,'..','..','cypress','support', 'chainable.ts'); 8 | 9 | const fixturesSrc=path.join(basepath,'node_modules','umbraco-cypress-testhelpers','cypress','fixtures','prevaluesource.txt'); 10 | const fixturesDst = path.join(basepath,'cypress','fixtures', 'prevaluesouce.txt'); 11 | 12 | try { 13 | if (fs.existsSync(src)) { 14 | console.log('Copy chainable.ts file'); 15 | 16 | ncp(src, dst); 17 | } 18 | } catch(err) { 19 | console.error(err) 20 | } 21 | try { 22 | if (fs.existsSync(fixturesSrc)) { 23 | console.log('Copy prevaluesource.txt file'); 24 | ncp(fixturesSrc, fixturesDst); 25 | } 26 | } catch(err) { 27 | console.error(fixturesDst) 28 | } -------------------------------------------------------------------------------- /src/cms/builders/content/contentBuilder.ts: -------------------------------------------------------------------------------- 1 | import { ContentVariantBuilder } from './contentVariantBuilder'; 2 | 3 | export class ContentBuilder { 4 | id; 5 | contentTypeAlias; 6 | parentId; 7 | action; 8 | expireDate; 9 | releaseDate; 10 | templateAlias; 11 | 12 | contentVariantBuilders; 13 | 14 | constructor() { 15 | this.contentVariantBuilders = []; 16 | } 17 | 18 | withContentTypeAlias(contentTypeAlias) { 19 | this.contentTypeAlias = contentTypeAlias; 20 | return this; 21 | } 22 | 23 | withTemplateAlias(templateAlias) { 24 | this.templateAlias = templateAlias; 25 | return this; 26 | } 27 | 28 | withAction(action) { 29 | this.action = action; 30 | return this; 31 | } 32 | 33 | withParent(parentId) { 34 | this.parentId = parentId; 35 | return this; 36 | } 37 | 38 | addVariant() { 39 | const builder = new ContentVariantBuilder(this); 40 | 41 | this.contentVariantBuilders.push(builder); 42 | 43 | return builder; 44 | } 45 | 46 | build() { 47 | return { 48 | id: this.id || 0, 49 | contentTypeAlias: this.contentTypeAlias || null, 50 | parentId: this.parentId || -1, 51 | action: this.action || 'publishNew', 52 | variants: this.contentVariantBuilders.map((builder) => { 53 | return builder.build(); 54 | }), 55 | expireDate: this.expireDate || null, 56 | releaseDate: this.releaseDate || null, 57 | templateAlias: this.templateAlias || null, 58 | }; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/cms/builders/content/contentVariantBuilder.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | import { ContentVariantPropertyBuilder } from './contentVariantPropertyBuilder'; 3 | 4 | export class ContentVariantBuilder { 5 | parentBuilder; 6 | id; 7 | name; 8 | culture; 9 | publish; 10 | save; 11 | releaseDate; 12 | expireDate; 13 | 14 | contentVariantPropertyBuilders; 15 | 16 | constructor(parentBuilder) { 17 | this.parentBuilder = parentBuilder; 18 | this.contentVariantPropertyBuilders = []; 19 | } 20 | 21 | addProperty() { 22 | const builder = new ContentVariantPropertyBuilder(this); 23 | 24 | this.contentVariantPropertyBuilders.push(builder); 25 | 26 | return builder; 27 | } 28 | withCulture(culture) { 29 | this.culture = culture; 30 | return this; 31 | } 32 | withPublish(publish) { 33 | this.publish = publish; 34 | return this; 35 | } 36 | withSave(save) { 37 | this.save = save; 38 | return this; 39 | } 40 | withName(name) { 41 | this.name = name; 42 | return this; 43 | } 44 | done() { 45 | return this.parentBuilder; 46 | } 47 | 48 | build() { 49 | const name = this.name || faker.random.uuid(); 50 | 51 | return { 52 | name, 53 | id: this.id || 0, 54 | properties: this.contentVariantPropertyBuilders.map((builder) => { 55 | return builder.build(); 56 | }), 57 | culture: this.culture || null, 58 | publish: this.publish || false, 59 | save: this.save || false, 60 | releaseDate: this.releaseDate || null, 61 | expireDate: this.expireDate || null, 62 | }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/cms/builders/content/contentVariantPropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | export class ContentVariantPropertyBuilder { 2 | parentBuilder; 3 | 4 | id; 5 | alias; 6 | value; 7 | 8 | constructor(parentBuilder) { 9 | this.parentBuilder = parentBuilder; 10 | } 11 | 12 | withAlias(alias) { 13 | this.alias = alias; 14 | return this; 15 | } 16 | 17 | withValue(value) { 18 | this.value = value; 19 | return this; 20 | } 21 | 22 | done() { 23 | return this.parentBuilder; 24 | } 25 | 26 | build() { 27 | return { 28 | id: this.id || 0, 29 | alias: this.alias || null, 30 | value: this.value || null, 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/cms/builders/content/index.ts: -------------------------------------------------------------------------------- 1 | export { ContentBuilder } from './contentBuilder'; 2 | export { ContentVariantBuilder } from './contentVariantBuilder'; 3 | export { ContentVariantPropertyBuilder } from './contentVariantPropertyBuilder'; 4 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/approvedColorPickerTypeDataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { ApprovedColourPickerDataType } from '../../models/dataTypes/approvedColourPickerDataType'; 2 | import { DataTypeBuilder } from './dataTypeBuilder'; 3 | 4 | export class ApprovedColorPickerDataTypeBuilder extends DataTypeBuilder { 5 | constructor( 6 | private approvedColourPickerDataTypeBuilder: ApprovedColourPickerDataType = new ApprovedColourPickerDataType(), 7 | ) { 8 | super(approvedColourPickerDataTypeBuilder); 9 | } 10 | withPrevalues(value: string[], multiSelect = false) { 11 | this.approvedColourPickerDataTypeBuilder.addPrevalues(value, multiSelect); 12 | return this; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/checkBoxListDataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DataTypeBuilder } from './dataTypeBuilder'; 2 | import { CheckBoxListDataType } from '../../models/dataTypes/checkBoxListDataType'; 3 | 4 | export class CheckBoxListDataTypeBuilder extends DataTypeBuilder { 5 | constructor(private checkBoxListDataType: CheckBoxListDataType = new CheckBoxListDataType()) { 6 | super(checkBoxListDataType); 7 | } 8 | withPrevalues(value: string[], multiSelect = false) { 9 | this.checkBoxListDataType.addPrevalues(value, multiSelect); 10 | return this; 11 | } 12 | } -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/dataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from '../../models/dataTypes/dataType'; 2 | 3 | export class DataTypeBuilder { 4 | constructor(public dataType: DataType) {} 5 | public withSaveAction() { 6 | this.dataType.action = 'save'; 7 | return this; 8 | } 9 | public withSaveNewAction() { 10 | this.dataType.action = 'saveNew'; 11 | return this; 12 | } 13 | public withId(id) { 14 | this.dataType.id = id; 15 | return this; 16 | } 17 | public withName(name) { 18 | this.dataType.name = name; 19 | return this; 20 | } 21 | 22 | public build(): DataType { 23 | return this.dataType; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/dropDownDataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DataTypeBuilder } from './dataTypeBuilder'; 2 | import { DropDownDataType } from '../../models/dataTypes/dropDownDataType'; 3 | 4 | export class DropDownDataTypeBuilder extends DataTypeBuilder { 5 | constructor(private dropDownDataType: DropDownDataType = new DropDownDataType()) { 6 | super(dropDownDataType); 7 | } 8 | withPrevalues(value: string[], multiSelect = false) { 9 | this.dropDownDataType.addPrevalues(value, multiSelect); 10 | return this; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/formPickerDataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DataTypeBuilder } from './dataTypeBuilder'; 2 | import { FormPickerDataType } from '../../models/dataTypes/formPickerDataType'; 3 | 4 | export class FormPickerDataTypeBuilder extends DataTypeBuilder { 5 | constructor(private formPickerDataType: FormPickerDataType = new FormPickerDataType()) { 6 | super(formPickerDataType); 7 | } 8 | 9 | withAllowedForms(formIds: string[]) { 10 | this.formPickerDataType.addPrevalues(formIds); 11 | return this; 12 | } 13 | withAllowedForm(formId: string) { 14 | return this.withAllowedForms([formId]); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/gridAreaBuilder.ts: -------------------------------------------------------------------------------- 1 | import { GridRowConfigBuilder } from './gridRowConfigBuilder'; 2 | 3 | export class GridAreaBuilder { 4 | parentBuilder; 5 | gridSize; 6 | editors; 7 | allowed; 8 | maxItems; 9 | 10 | constructor(parentBuilder: GridRowConfigBuilder) { 11 | this.parentBuilder = parentBuilder; 12 | this.editors = []; 13 | this.allowed = []; 14 | } 15 | 16 | withGridSize(gridSize: number) { 17 | this.gridSize = gridSize; 18 | return this; 19 | } 20 | 21 | withMaxItems(maxItems: number) { 22 | this.maxItems = maxItems; 23 | return this; 24 | } 25 | 26 | withEditor(editor) { 27 | this.editors.push(editor); 28 | return this; 29 | } 30 | 31 | withAllowRTE() { 32 | this.allowed.push('rte'); 33 | return this; 34 | } 35 | 36 | withAllowImage() { 37 | this.allowed.push('media'); 38 | return this; 39 | } 40 | 41 | withAllowMacro() { 42 | this.allowed.push('macro'); 43 | return this; 44 | } 45 | 46 | withAllowEmbed() { 47 | this.allowed.push('embed'); 48 | return this; 49 | } 50 | 51 | withAllowHeadline() { 52 | this.allowed.push('headline'); 53 | return this; 54 | } 55 | 56 | withAllowQuote() { 57 | this.allowed.push('quote'); 58 | return this; 59 | } 60 | 61 | withAllowAll() { 62 | this.allowed = []; 63 | return this; 64 | } 65 | 66 | done(): GridRowConfigBuilder { 67 | return this.parentBuilder; 68 | } 69 | 70 | build() { 71 | const area = { grid: this.gridSize }; 72 | 73 | if (this.editors.length > 0) { 74 | Object.assign(area, { editors: this.editors }); 75 | } 76 | 77 | if (this.allowed.length > 0) { 78 | Object.assign(area, { 79 | allowAll: false, 80 | allowed: this.allowed, 81 | }); 82 | } 83 | 84 | if (this.maxItems) { 85 | Object.assign(area, { maxItems: this.maxItems }); 86 | } 87 | 88 | return area; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/gridLayoutBuilder.ts: -------------------------------------------------------------------------------- 1 | import { GridDataTypeBuilder } from './../gridDataTypeBuilder'; 2 | import { SectionBuilder } from './sectionBuilder'; 3 | 4 | export class GridLayoutBuilder { 5 | parentBuilder: GridDataTypeBuilder; 6 | name; 7 | sectionBuilders; 8 | 9 | constructor(parrentBuilder: GridDataTypeBuilder) { 10 | this.parentBuilder = parrentBuilder; 11 | this.sectionBuilders = []; 12 | } 13 | 14 | withName(name) { 15 | this.name = name; 16 | return this; 17 | } 18 | 19 | addSection(sectionBuilder?: SectionBuilder) { 20 | const builder = sectionBuilder === null || sectionBuilder === undefined ? new SectionBuilder(this) : sectionBuilder; 21 | this.sectionBuilders.push(builder); 22 | return builder; 23 | } 24 | 25 | withSimpleSection(gridSize: number) { 26 | this.addSection().withGridSize(gridSize).done(); 27 | return this; 28 | } 29 | 30 | done(): GridDataTypeBuilder { 31 | return this.parentBuilder; 32 | } 33 | 34 | build() { 35 | return { 36 | name: this.name, 37 | sections: this.sectionBuilders.map((builder) => { 38 | return builder.build(); 39 | }), 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/gridRowConfigBuilder.ts: -------------------------------------------------------------------------------- 1 | import { GridDataTypeBuilder } from '../gridDataTypeBuilder'; 2 | import { GridAreaBuilder } from './gridAreaBuilder'; 3 | 4 | export class GridRowConfigBuilder { 5 | parentBuilder; 6 | label; 7 | name; 8 | areas; 9 | allowed; 10 | 11 | constructor(parentBuilder: GridDataTypeBuilder) { 12 | this.parentBuilder = parentBuilder; 13 | this.areas = []; 14 | } 15 | 16 | withName(name) { 17 | this.name = name; 18 | return this; 19 | } 20 | 21 | withLabel(label) { 22 | this.label = label; 23 | return this; 24 | } 25 | 26 | withAllowed(allowed: boolean) { 27 | this.allowed = allowed; 28 | return this; 29 | } 30 | 31 | addArea(areaBuilder?: GridAreaBuilder) { 32 | const builder = areaBuilder === null || areaBuilder === undefined ? new GridAreaBuilder(this) : areaBuilder; 33 | 34 | this.areas.push(builder); 35 | return builder; 36 | } 37 | 38 | withSimpleArea(gridSize: number) { 39 | this.addArea().withGridSize(gridSize).done(); 40 | return this; 41 | } 42 | 43 | done(): GridDataTypeBuilder { 44 | return this.parentBuilder; 45 | } 46 | 47 | build() { 48 | if (this.allowed) { 49 | return { 50 | allowed: this.allowed, 51 | name: this.name, 52 | label: this.label || this.name, 53 | areas: this.areas.map((builder) => { 54 | return builder.build(); 55 | }), 56 | }; 57 | } 58 | return { 59 | name: this.name, 60 | label: this.label || this.name, 61 | areas: this.areas.map((builder) => { 62 | return builder.build(); 63 | }), 64 | }; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/gridRteBuilder.ts: -------------------------------------------------------------------------------- 1 | import { GridDataTypeBuilder } from '../gridDataTypeBuilder'; 2 | import { RteToolbarOptionsBuilder } from './rteToolbarOptionsBuilder'; 3 | 4 | export class GridRteBuilder { 5 | parentBuilder; 6 | maxImageSize; 7 | mode; 8 | stylesheets; 9 | toolbarOptionsBuilder; 10 | dimensions; 11 | 12 | constructor(parentBuilder: GridDataTypeBuilder) { 13 | this.parentBuilder = parentBuilder; 14 | this.stylesheets = []; 15 | } 16 | 17 | withClassicMode() { 18 | this.mode = 'classic'; 19 | return this; 20 | } 21 | 22 | withDistractionFreeMode() { 23 | this.mode = 'distraction-free'; 24 | return this; 25 | } 26 | 27 | withMaxImageSize(imageSize: number) { 28 | this.maxImageSize = imageSize; 29 | return this; 30 | } 31 | 32 | withDimensions(width: number, height: number) { 33 | this.dimensions = { 34 | width: width, 35 | height: height, 36 | }; 37 | return this; 38 | } 39 | 40 | withStylesheet(virtualPath: string) { 41 | this.stylesheets.push(virtualPath); 42 | return this; 43 | } 44 | 45 | addToolBarOptions(optionsBuilder?: RteToolbarOptionsBuilder) { 46 | const builder = 47 | optionsBuilder === null || optionsBuilder === undefined ? new RteToolbarOptionsBuilder(this) : optionsBuilder; 48 | 49 | this.toolbarOptionsBuilder = builder; 50 | return builder; 51 | } 52 | 53 | done() { 54 | return this.parentBuilder; 55 | } 56 | 57 | build() { 58 | const RTE = { 59 | maxImageSize: this.maxImageSize || 500, 60 | mode: this.mode || 'classic', 61 | stylesheets: this.stylesheets, 62 | toolbar: this.toolbarOptionsBuilder.build(), 63 | }; 64 | 65 | if (this.dimensions) { 66 | Object.assign(RTE, { dimensions: this.dimensions }); 67 | } 68 | 69 | return RTE; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/gridSettingsBuilder.ts: -------------------------------------------------------------------------------- 1 | import { GridDataTypeBuilder } from '../gridDataTypeBuilder'; 2 | 3 | export class GridSettingsbuilder { 4 | parentBuilder; 5 | description; 6 | key; 7 | label; 8 | view; 9 | 10 | constructor(parentbuilder: GridDataTypeBuilder) { 11 | this.parentBuilder = parentbuilder; 12 | } 13 | 14 | withDescription(description: string) { 15 | this.description = description; 16 | return this; 17 | } 18 | 19 | withKey(key: string) { 20 | this.key = key; 21 | return this; 22 | } 23 | 24 | withLabel(label: string) { 25 | this.label = label; 26 | return this; 27 | } 28 | 29 | withView(view: string) { 30 | this.view = view; 31 | return this; 32 | } 33 | 34 | done(): GridDataTypeBuilder { 35 | return this.parentBuilder; 36 | } 37 | 38 | build() { 39 | return { 40 | description: this.description, 41 | key: this.key, 42 | label: this.label, 43 | view: this.view, 44 | }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/gridStylesBuilder.ts: -------------------------------------------------------------------------------- 1 | import { GridDataTypeBuilder } from '../gridDataTypeBuilder'; 2 | import { GridSettingsbuilder } from './gridSettingsBuilder'; 3 | 4 | export class GridStylesBuilder extends GridSettingsbuilder { 5 | modifier; 6 | 7 | constructor(parentbuilder: GridDataTypeBuilder) { 8 | super(parentbuilder); 9 | } 10 | 11 | withModifier(modifier: string) { 12 | this.modifier = modifier; 13 | return this; 14 | } 15 | 16 | build() { 17 | return { 18 | description: this.description, 19 | key: this.key, 20 | label: this.label, 21 | view: this.view, 22 | modifier: this.modifier, 23 | }; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/index.ts: -------------------------------------------------------------------------------- 1 | export { GridLayoutBuilder } from './gridLayoutBuilder'; 2 | export { SectionBuilder } from './sectionBuilder'; 3 | export { GridRowConfigBuilder } from './gridRowConfigBuilder'; 4 | export { GridAreaBuilder } from './gridAreaBuilder'; 5 | export { GridRteBuilder } from './gridRteBuilder'; 6 | export { RteToolbarOptionsBuilder } from './rteToolbarOptionsBuilder'; 7 | export { GridSettingsbuilder } from './gridSettingsBuilder'; 8 | export { GridStylesBuilder } from './gridStylesBuilder'; 9 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/gridBuilders/sectionBuilder.ts: -------------------------------------------------------------------------------- 1 | import { GridLayoutBuilder } from './gridLayoutBuilder'; 2 | 3 | export class SectionBuilder { 4 | parrentBuilder; 5 | grid; 6 | allowed; 7 | 8 | constructor(parrentBuilder: GridLayoutBuilder) { 9 | this.parrentBuilder = parrentBuilder; 10 | this.allowed = []; 11 | } 12 | 13 | withGridSize(gridSize: number) { 14 | this.grid = gridSize; 15 | return this; 16 | } 17 | 18 | withAllowAll() { 19 | this.allowed = []; 20 | return this; 21 | } 22 | 23 | withAllowed(allowedName: string) { 24 | this.allowed.push(allowedName); 25 | return this; 26 | } 27 | 28 | done(): GridLayoutBuilder { 29 | return this.parrentBuilder; 30 | } 31 | 32 | build() { 33 | const grid = { 34 | grid: this.grid, 35 | allowAll: true, 36 | }; 37 | 38 | if (this.allowed.length > 0) { 39 | Object.assign(grid, { allowed: this.allowed }); 40 | grid.allowAll = false; 41 | } 42 | 43 | return grid; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/index.ts: -------------------------------------------------------------------------------- 1 | export { FormPickerDataTypeBuilder } from './formPickerDataTypeBuilder'; 2 | export { LabelDataTypeBuilder } from './labelDataTypeBuilder'; 3 | export { TextBoxDataTypeBuilder } from './textBoxDataTypeBuilder'; 4 | export { DropDownDataTypeBuilder } from './dropDownDataTypeBuilder'; 5 | export { GridDataTypeBuilder } from './gridDataTypeBuilder'; 6 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/labelDataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DataTypeBuilder } from './dataTypeBuilder'; 2 | import { LabelDataType } from '../../models/dataTypes/labelDataType'; 3 | 4 | export class LabelDataTypeBuilder extends DataTypeBuilder { 5 | constructor(private labelDataType: LabelDataType = new LabelDataType()) { 6 | super(labelDataType); 7 | this.withStringValueType(); 8 | } 9 | 10 | withStringValueType() { 11 | return this.withValueType('STRING'); 12 | } 13 | 14 | withDecimalValueType() { 15 | return this.withValueType('DECIMAL'); 16 | } 17 | 18 | withDateTimeValueType() { 19 | return this.withValueType('DATETIME'); 20 | } 21 | 22 | withTimeValueType() { 23 | return this.withValueType('TIME'); 24 | } 25 | 26 | withIntegerValueType() { 27 | return this.withValueType('INT'); 28 | } 29 | 30 | withBigIntegerValueType() { 31 | return this.withValueType('BIGINT'); 32 | } 33 | 34 | withLongStringValueType() { 35 | return this.withValueType('TEXT'); 36 | } 37 | 38 | withValueType(type) { 39 | this.labelDataType.addPrevalues(type); 40 | return this; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/cms/builders/dataTypes/textBoxDataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DataTypeBuilder } from './dataTypeBuilder'; 2 | import { TextBoxDataType } from '../../models/dataTypes/textBoxDataType'; 3 | 4 | export class TextBoxDataTypeBuilder extends DataTypeBuilder { 5 | constructor(private textBoxDataType: TextBoxDataType = new TextBoxDataType()) { 6 | super(textBoxDataType); 7 | } 8 | withMaxChars(chars: number) { 9 | this.textBoxDataType.addPrevalues(chars); 10 | return this; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/documentTypeTabBuilder.ts: -------------------------------------------------------------------------------- 1 | import DocumentTypeGroupBuilder from "./documentTypeGroupBuilder"; 2 | import faker from 'faker'; 3 | 4 | export default class DocumentTypeTabBuilder extends DocumentTypeGroupBuilder { 5 | documentTypeGroupBuilders; 6 | 7 | constructor(parentBuilder) { 8 | super(parentBuilder); 9 | this.documentTypeGroupBuilders = []; 10 | } 11 | 12 | addGroup(documentTypeGroupBuilder?: DocumentTypeGroupBuilder) { 13 | const builder = 14 | documentTypeGroupBuilder === null || documentTypeGroupBuilder === undefined 15 | ? new DocumentTypeGroupBuilder(this) 16 | : documentTypeGroupBuilder; 17 | this.documentTypeGroupBuilders.push(builder); 18 | return builder; 19 | } 20 | 21 | done(){ 22 | this.documentTypeGroupBuilders.forEach(element => { 23 | element.alias = this.getAlias() + "/" + element.getAlias(); 24 | this.parentBuilder.documentTypeGroupBuilders.push(element); 25 | }); 26 | return this.parentBuilder; 27 | } 28 | 29 | build(){ 30 | const name = this.name || faker.random.uuid() 31 | return { 32 | id: this.id || -1, 33 | inherited: this.inherited || false, 34 | name: this.name || name, 35 | alias: this.getAlias(), 36 | sortOrder: this.sortOrder || 0, 37 | type : 1, 38 | properties: this.documentTypeGroupPropertyBuilders.map((builder) => { 39 | return builder.build(); 40 | }), 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/index.ts: -------------------------------------------------------------------------------- 1 | export { DocumentTypeBuilder } from './documentTypeBuilder'; 2 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/approvedColorPickerTypeDataTypeBuilder.ts: -------------------------------------------------------------------------------- 1 | import { ApprovedColourPickerDataType } from 'src/cms/models/dataTypes/approvedColourPickerDataType'; 2 | import { DataTypeBuilder } from '../../dataTypes/dataTypeBuilder'; 3 | 4 | export class ApprovedColorPickerDataTypeBuilder extends DataTypeBuilder { 5 | constructor(private approvedColourPickerDataTypeBuilder: ApprovedColourPickerDataType = new ApprovedColourPickerDataType()) { 6 | super(approvedColourPickerDataTypeBuilder) 7 | } 8 | 9 | withPrevalues(value: string[], multiSelect = false) { 10 | this.approvedColourPickerDataTypeBuilder.addPrevalues(value, multiSelect); 11 | return this; 12 | } 13 | } -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/contentPickerTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DocumentTypePropertyBuilder } from './documentTypePropertyBuilder'; 2 | 3 | export class ContentPickerPropertyBuilder extends DocumentTypePropertyBuilder { 4 | constructor(parentBuilder) { 5 | super(parentBuilder); 6 | this.dataTypeId = 1046; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/customDocumentTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DocumentTypePropertyBuilder } from './documentTypePropertyBuilder'; 2 | 3 | export class CustomDocumentTypePropertyBuilder extends DocumentTypePropertyBuilder { 4 | constructor(parentBuilder, dataTypeId) { 5 | super(parentBuilder); 6 | this.dataTypeId = dataTypeId; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/documentTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | import camelize from 'camelize'; 3 | import { AliasHelper } from '../../../../helpers/aliasHelper'; 4 | 5 | export class DocumentTypePropertyBuilder { 6 | parentBuilder; 7 | 8 | alias; 9 | value; 10 | allowCultureVariant; 11 | dataTypeId; 12 | label; 13 | sortOrder; 14 | validation; 15 | 16 | constructor(parentBuilder) { 17 | this.parentBuilder = parentBuilder; 18 | } 19 | 20 | withDataTypeId(dataTypeId) { 21 | this.dataTypeId = dataTypeId; 22 | return this; 23 | } 24 | withLabel(label) { 25 | this.label = label; 26 | return this; 27 | } 28 | withAlias(alias) { 29 | this.alias = alias; 30 | return this; 31 | } 32 | withValue(value) { 33 | this.value = value; 34 | return this; 35 | } 36 | done() { 37 | return this.parentBuilder; 38 | } 39 | 40 | build() { 41 | const label = this.label || faker.random.uuid(); 42 | const alias = this.alias || 'a' + camelize(label); 43 | 44 | return { 45 | alias, 46 | value: this.value || '', 47 | allowCultureVariant: this.allowCultureVariant || false, 48 | dataTypeId: this.dataTypeId || -1, 49 | label, 50 | sortOrder: this.sortOrder || 0, 51 | validation: this.validation || { mandatory: false, pattern: null }, 52 | }; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/dropDownDocumentTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DocumentTypePropertyBuilder } from './documentTypePropertyBuilder'; 2 | 3 | export class DropDownDocumentTypePropertyBuilder extends DocumentTypePropertyBuilder { 4 | constructor(parentBuilder) { 5 | super(parentBuilder); 6 | this.dataTypeId = -39; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/formPickerDocumentTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DocumentTypePropertyBuilder } from './documentTypePropertyBuilder'; 2 | 3 | export class FormPickerDocumentTypePropertyBuilder extends DocumentTypePropertyBuilder { 4 | constructor(parentBuilder) { 5 | super(parentBuilder); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/index.ts: -------------------------------------------------------------------------------- 1 | export { FormPickerDocumentTypePropertyBuilder } from './formPickerDocumentTypePropertyBuilder'; 2 | export { TextBoxDocumentTypePropertyBuilder } from './textBoxDocumentTypePropertyBuilder'; 3 | export { DropDownDocumentTypePropertyBuilder } from './dropDownDocumentTypePropertyBuilder'; 4 | export { ContentPickerPropertyBuilder } from './contentPickerTypePropertyBuilder'; 5 | export { RichTextDocumentTypePropertyEditor } from './richTextDocumentTypePropertyBuilder'; 6 | export { CustomDocumentTypePropertyBuilder } from './customDocumentTypePropertyBuilder'; 7 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/richTextDocumentTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DocumentTypePropertyBuilder } from './documentTypePropertyBuilder'; 2 | 3 | export class RichTextDocumentTypePropertyEditor extends DocumentTypePropertyBuilder { 4 | constructor(parentBuilder) { 5 | super(parentBuilder); 6 | this.dataTypeId = -87; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/textBoxDocumentTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DocumentTypePropertyBuilder } from './documentTypePropertyBuilder'; 2 | 3 | export class TextBoxDocumentTypePropertyBuilder extends DocumentTypePropertyBuilder { 4 | constructor(parentBuilder) { 5 | super(parentBuilder); 6 | this.dataTypeId = -88; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/cms/builders/documentTypes/properties/urlPickerTypePropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | import { DocumentTypePropertyBuilder } from './documentTypePropertyBuilder'; 2 | 3 | export class UrlPickerPropertyBuilder extends DocumentTypePropertyBuilder { 4 | constructor(parentBuilder) { 5 | super(parentBuilder); 6 | this.dataTypeId = 1050; 7 | } 8 | } -------------------------------------------------------------------------------- /src/cms/builders/index.ts: -------------------------------------------------------------------------------- 1 | export { ContentBuilder } from './content/contentBuilder'; 2 | export { ContentVariantBuilder } from './content/contentVariantBuilder'; 3 | export { ContentVariantPropertyBuilder } from './content/contentVariantPropertyBuilder'; 4 | 5 | export { FormPickerDataTypeBuilder } from './dataTypes/formPickerDataTypeBuilder'; 6 | export { LabelDataTypeBuilder } from './dataTypes/labelDataTypeBuilder'; 7 | export { TextBoxDataTypeBuilder } from './dataTypes/textBoxDataTypeBuilder'; 8 | export { DropDownDataTypeBuilder } from './dataTypes/dropDownDataTypeBuilder'; 9 | 10 | export { DocumentTypeBuilder } from './documentTypes/documentTypeBuilder'; 11 | 12 | export { TemplateBuilder } from './templates/templateBuilder'; 13 | 14 | export { UserGroupBuilder } from './userGroups/userGroupBuilder'; 15 | export { UserBuilder } from './user/userBuilder'; 16 | export { MediaBuilder } from './media' -------------------------------------------------------------------------------- /src/cms/builders/macroBuilder.ts: -------------------------------------------------------------------------------- 1 | import { AliasHelper } from '../../helpers/aliasHelper'; 2 | 3 | export class MacroBuilder { 4 | name; 5 | renderInEditor; 6 | useInEditor; 7 | cacheByPage; 8 | cacheByUser; 9 | partialViewMacro; 10 | 11 | withName(name) { 12 | this.name = name; 13 | return this; 14 | } 15 | 16 | withRenderInEditor() { 17 | this.renderInEditor = true; 18 | return this; 19 | } 20 | 21 | withUseInEditor() { 22 | this.useInEditor = true; 23 | return this; 24 | } 25 | 26 | withCacheByPage() { 27 | this.cacheByPage = true; 28 | return this; 29 | } 30 | 31 | withCacheByUser() { 32 | this.cacheByUser = true; 33 | return this; 34 | } 35 | 36 | withPartialViewMacro(partialView) { 37 | this.partialViewMacro = partialView; 38 | return this; 39 | } 40 | 41 | build() { 42 | return { 43 | name: this.name, 44 | renderInEditor: this.renderInEditor || true, 45 | useInEditor: this.useInEditor || false, 46 | cacheByPage: this.cacheByPage || false, 47 | cacheByUser: this.cacheByUser || false, 48 | partialView: this.partialViewMacro || null, 49 | }; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/cms/builders/media/index.ts: -------------------------------------------------------------------------------- 1 | export { MediaBuilder } from './mediaBuilder'; 2 | export { MediaPropertyBuilder } from './mediaPropertyBuilder'; 3 | -------------------------------------------------------------------------------- /src/cms/builders/media/mediaBuilder.ts: -------------------------------------------------------------------------------- 1 | import {MediaPropertyBuilder} from './mediaPropertyBuilder'; 2 | 3 | export class MediaBuilder { 4 | id; 5 | properties; 6 | name; 7 | contentTypeAlias; 8 | parentId; 9 | action; 10 | mediaPropertyBuilder; 11 | 12 | constructor() { 13 | this.mediaPropertyBuilder = []; 14 | } 15 | 16 | addProperty() { 17 | const builder = new MediaPropertyBuilder(this); 18 | this.mediaPropertyBuilder.push(builder); 19 | return builder; 20 | } 21 | 22 | withName(name) { 23 | this.name = name; 24 | return this; 25 | } 26 | 27 | withContentTypeAlias(contentTypeAlias) { 28 | this.contentTypeAlias = contentTypeAlias; 29 | return this; 30 | } 31 | 32 | build() { 33 | return { 34 | id: this.id || '0', 35 | properties: this.mediaPropertyBuilder.map((builder) => { 36 | return builder.build(); 37 | }), 38 | name: this.name, 39 | contentTypeAlias: this.contentTypeAlias, 40 | parentId: this.parentId || '-1', 41 | action: this.action || 'saveNew' 42 | }; 43 | } 44 | } -------------------------------------------------------------------------------- /src/cms/builders/media/mediaPropertyBuilder.ts: -------------------------------------------------------------------------------- 1 | export class MediaPropertyBuilder { 2 | parentBuilder; 3 | id; 4 | alias; 5 | value; 6 | 7 | constructor(parentBuilder) { 8 | this.parentBuilder = parentBuilder; 9 | } 10 | 11 | withAlias(alias) { 12 | this.alias = alias; 13 | return this; 14 | } 15 | 16 | withValue(value) { 17 | this.value = value; 18 | return this; 19 | } 20 | 21 | done() { 22 | return this.parentBuilder; 23 | } 24 | 25 | build() { 26 | return { 27 | id: this.id || 0, 28 | alias: this.alias || null, 29 | value: this.value || null, 30 | }; 31 | } 32 | } -------------------------------------------------------------------------------- /src/cms/builders/partialViewMacros/partialViewMacroBuilder.ts: -------------------------------------------------------------------------------- 1 | import { PartialViewMacro } from '../../models/partialViewMacros/partialViewMacro'; 2 | 3 | export class PartialViewMacroBuilder { 4 | constructor(public partialViewMacro: PartialViewMacro = new PartialViewMacro()) {} 5 | 6 | public withName(name) { 7 | this.partialViewMacro.name = name; 8 | return this; 9 | } 10 | public withContent(content) { 11 | this.partialViewMacro.content = content; 12 | return this; 13 | } 14 | 15 | public build(): PartialViewMacro { 16 | return this.partialViewMacro; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/cms/builders/partialViews/partialViewBuilder.ts: -------------------------------------------------------------------------------- 1 | export class PartialViewBuilder { 2 | name; 3 | content; 4 | filetype; 5 | id; 6 | notifications; 7 | path; 8 | snippet; 9 | virtualPath; 10 | 11 | withContent(content) { 12 | this.content = content; 13 | return this; 14 | } 15 | 16 | withName(name) { 17 | this.name = name; 18 | return this; 19 | } 20 | 21 | withId(id: number) { 22 | this.id = id; 23 | return this; 24 | } 25 | 26 | build() { 27 | return { 28 | name: this.name, 29 | content: this.content, 30 | filetype: this.filetype || 'partialViews', 31 | id: this.id || 0, 32 | notifications: this.notifications || [], 33 | path: this.path || null, 34 | snippet: this.snippet || null, 35 | virtualPath: this.virtualPath || '/Views/Partials/', 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/cms/builders/scriptbuilder.ts: -------------------------------------------------------------------------------- 1 | export class ScriptBuilder { 2 | content; 3 | fileType; 4 | id; 5 | name; 6 | notifications; 7 | path; 8 | snippet; 9 | virtualPath; 10 | 11 | withContent(content) { 12 | this.content = content; 13 | return this; 14 | } 15 | 16 | withName(name) { 17 | this.name = name; 18 | return this; 19 | } 20 | 21 | build() { 22 | return { 23 | name: this.name, 24 | content: this.content, 25 | filetype: this.fileType || 'scripts', 26 | id: this.id || '0', 27 | notifications: this.notifications || [], 28 | path: this.path || null, 29 | snippet: this.snippet || null, 30 | virtualPath: this.virtualPath || '/scripts/', 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/cms/builders/stylesheetBuilder.ts: -------------------------------------------------------------------------------- 1 | export class StylesheetBuilder { 2 | content; 3 | fileType; 4 | id; 5 | name; 6 | notifications; 7 | path; 8 | snippet; 9 | virtualPath; 10 | 11 | withContent(content) { 12 | this.content = content; 13 | return this; 14 | } 15 | 16 | withName(name) { 17 | this.name = name; 18 | return this; 19 | } 20 | 21 | build() { 22 | return { 23 | name: this.name, 24 | content: this.content, 25 | filetype: this.fileType || 'stylesheets', 26 | id: this.id || '0', 27 | notifications: this.notifications || [], 28 | path: this.path || null, 29 | snippet: this.snippet || null, 30 | virtualPath: this.virtualPath || '/css/', 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/cms/builders/templates/index.ts: -------------------------------------------------------------------------------- 1 | export { TemplateBuilder } from './templateBuilder'; 2 | -------------------------------------------------------------------------------- /src/cms/builders/templates/templateBuilder.ts: -------------------------------------------------------------------------------- 1 | import { Template } from '../../models/template'; 2 | 3 | export class TemplateBuilder { 4 | constructor(private template: Template = new Template()) {} 5 | 6 | withId(id) { 7 | this.template.id = id; 8 | return this; 9 | } 10 | withKey(key) { 11 | this.template.key = key; 12 | return this; 13 | } 14 | withName(name) { 15 | this.template.name = name; 16 | return this; 17 | } 18 | withAlias(alias) { 19 | this.template.alias = alias; 20 | return this; 21 | } 22 | withContent(content) { 23 | this.template.content = content; 24 | return this; 25 | } 26 | withPath(path) { 27 | this.template.path = path; 28 | return this; 29 | } 30 | withVirtualPath(virtualPath) { 31 | this.template.virtualPath = virtualPath; 32 | return this; 33 | } 34 | withMasterTemplateAlias(masterTemplateAlias) { 35 | this.template.masterTemplateAlias = masterTemplateAlias; 36 | return this; 37 | } 38 | withIsMasterTemplate(isMasterTemplate) { 39 | this.template.isMasterTemplate = isMasterTemplate; 40 | return this; 41 | } 42 | withNotifications(notifications) { 43 | this.template.notifications = notifications; 44 | return this; 45 | } 46 | 47 | public build(): Template { 48 | return this.template; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/cms/builders/user/index.ts: -------------------------------------------------------------------------------- 1 | export { UserBuilder } from './userBuilder'; -------------------------------------------------------------------------------- /src/cms/builders/user/userBuilder.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | 3 | export class UserBuilder { 4 | email: string; 5 | id: number; 6 | message: string; 7 | name: string; 8 | parentId: number; 9 | userGroups: string[]; 10 | 11 | 12 | constructor() { 13 | this.userGroups = []; 14 | } 15 | 16 | withEmail(email: string) { 17 | this.email = email; 18 | return this; 19 | } 20 | 21 | withId(id: number) { 22 | this.id = id; 23 | return this; 24 | } 25 | 26 | withName(name: string) { 27 | this.name = name; 28 | return this; 29 | } 30 | 31 | withParentId(parentId: number) { 32 | this.parentId = parentId; 33 | return this; 34 | } 35 | 36 | appendUserGroup(userGroup: string) { 37 | this.userGroups.push(userGroup); 38 | return this; 39 | } 40 | 41 | withUserGroups(userGroups: string[]) { 42 | this.userGroups = userGroups; 43 | return this; 44 | } 45 | 46 | build() { 47 | const email = this.email || 'test@test.com'; 48 | return { 49 | email: email, 50 | id: this.id || -1, 51 | message: this.message || "", 52 | name: this.name || email, 53 | parentId: this.parentId || -1, 54 | userGroups: this.userGroups || [] 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/cms/builders/userGroups/index.ts: -------------------------------------------------------------------------------- 1 | export { UserGroupBuilder } from './userGroupBuilder'; -------------------------------------------------------------------------------- /src/cms/builders/userGroups/nodePermissionBuilder.ts: -------------------------------------------------------------------------------- 1 | import {PermissionsBuilder} from "./permissionsBuilder"; 2 | 3 | export class NodePermissionBuilder extends PermissionsBuilder { 4 | nodeId: number; 5 | 6 | constructor(parentBuilder) { 7 | super(parentBuilder); 8 | } 9 | 10 | withNodeId(nodeId: number) { 11 | this.nodeId = nodeId; 12 | return this; 13 | } 14 | 15 | build(): any { 16 | const permissions = super.build(); 17 | 18 | // Programatically assigns a property with the nodeId, I.E {123: ["S"...]} where 123 is the ID. 19 | // It's important that enumerable is true, otherwise the property will not be serialized in the final result. 20 | let result = {}; 21 | result = Object.defineProperty(result, this.nodeId, { 22 | value: permissions, 23 | configurable: true, 24 | writable: true, 25 | enumerable: true 26 | }); 27 | 28 | return result; 29 | } 30 | } -------------------------------------------------------------------------------- /src/cms/builders/userGroups/nodePermissionCollectionBuilder.ts: -------------------------------------------------------------------------------- 1 | import {NodePermissionBuilder} from "./nodePermissionBuilder"; 2 | 3 | export class NodePermissionCollectionBuilder{ 4 | nodePermissionBuilders: NodePermissionBuilder[]; 5 | parentBuilder; 6 | 7 | constructor(parentBuilder) { 8 | this.nodePermissionBuilders = []; 9 | this.parentBuilder = parentBuilder; 10 | } 11 | 12 | addNodePermission(nodePermissionBuilder ?: NodePermissionBuilder) { 13 | const builder = 14 | nodePermissionBuilder === null || nodePermissionBuilder == undefined 15 | ? new NodePermissionBuilder(this) 16 | : nodePermissionBuilder; 17 | 18 | this.nodePermissionBuilders.push(builder); 19 | return builder; 20 | } 21 | 22 | done() { 23 | return this.parentBuilder 24 | } 25 | 26 | build() { 27 | let result = {}; 28 | 29 | // Each NodePermission builder returns an object, with the node ID as property key and the permission array as value 30 | // we need to merge all of these to a single object the backend will accept. 31 | this.nodePermissionBuilders.forEach((builder) => { 32 | result = Object.assign(result, builder.build()); 33 | }) 34 | 35 | return result; 36 | } 37 | } -------------------------------------------------------------------------------- /src/cms/models/cmsDocumentType.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An Umbraco Document Type 3 | * 4 | * @param {string} name Name of Document Type 5 | * @param {string} alias Alias of Document type 6 | * @param {number} id Optional integer ID of document type 7 | */ 8 | export class CmsDocumentType { 9 | constructor(public name: string, public alias: string, public id?: number) {} 10 | } 11 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/approvedColourPickerDataType.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from './dataType'; 2 | 3 | export class ApprovedColourPickerDataType extends DataType { 4 | constructor() { 5 | super(); 6 | this.selectedEditor = 'Umbraco.ColorPicker'; 7 | this.addPrevalues([], false); 8 | 9 | } 10 | public addPrevalues(value: string[], multiSelect = false) { 11 | this.preValues = [ 12 | { key: 'useLabel', value: multiSelect }, 13 | { 14 | key: 'items', 15 | value: value.map((val) => { 16 | return { value: val }; 17 | }), 18 | }, 19 | ]; 20 | } 21 | } -------------------------------------------------------------------------------- /src/cms/models/dataTypes/checkBoxListDataType.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from './dataType'; 2 | 3 | export class CheckBoxListDataType extends DataType { 4 | constructor() { 5 | super(); 6 | this.selectedEditor = 'Umbraco.CheckBoxList'; 7 | this.addPrevalues([], false); 8 | } 9 | public addPrevalues(value: string[], multiSelect = false) { 10 | this.preValues = [ 11 | { key: 'multiple', value: multiSelect }, 12 | { 13 | key: 'items', 14 | value: value.map((val) => { 15 | return { value: val }; 16 | }), 17 | }, 18 | ]; 19 | } 20 | } -------------------------------------------------------------------------------- /src/cms/models/dataTypes/dataType.ts: -------------------------------------------------------------------------------- 1 | import { DataTypePrevalue } from './dataTypePrevalue'; 2 | 3 | export abstract class DataType { 4 | public action = 'saveNew'; 5 | public id = 0; 6 | public name = ''; 7 | public parentId = -1; 8 | public selectedEditor = ''; 9 | protected preValues: DataTypePrevalue[]; 10 | 11 | public getPrevalues() { 12 | return this.preValues; 13 | } 14 | public abstract addPrevalues(value: any[] | any); 15 | } 16 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/dataTypePrevalue.ts: -------------------------------------------------------------------------------- 1 | export class DataTypePrevalue { 2 | key: string; 3 | value: any[] | any; 4 | } 5 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/dropDownDataType.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from './dataType'; 2 | 3 | export class DropDownDataType extends DataType { 4 | constructor() { 5 | super(); 6 | this.selectedEditor = 'Umbraco.DropDown.Flexible'; 7 | this.addPrevalues([], false); 8 | } 9 | public addPrevalues(value: string[], multiSelect = false) { 10 | this.preValues = [ 11 | { key: 'multiple', value: multiSelect }, 12 | { 13 | key: 'items', 14 | value: value.map((val) => { 15 | return { value: val }; 16 | }), 17 | }, 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/formPickerDataType.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from './dataType'; 2 | 3 | export class FormPickerDataType extends DataType { 4 | constructor() { 5 | super(); 6 | this.selectedEditor = 'UmbracoForms.FormPicker'; 7 | this.addPrevalues([]); 8 | } 9 | public addPrevalues(value: any[]) { 10 | this.preValues = [{ key: 'allowedForms', value }]; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/gridDataType.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from './dataType'; 2 | import { DataTypePrevalue } from './dataTypePrevalue'; 3 | 4 | export class GridDataType extends DataType { 5 | constructor() { 6 | super(); 7 | this.selectedEditor = 'Umbraco.Grid'; 8 | } 9 | 10 | public addPrevalues(values: DataTypePrevalue[]) { 11 | this.preValues = values; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/index.ts: -------------------------------------------------------------------------------- 1 | export { DataType } from './dataType'; 2 | export { DataTypePrevalue } from './dataTypePrevalue'; 3 | export { FormPickerDataType } from './formPickerDataType'; 4 | export { LabelDataType } from './labelDataType'; 5 | export { TextBoxDataType } from './textBoxDataType'; 6 | export { DropDownDataType } from './dropDownDataType'; 7 | export { GridDataType } from './gridDataType'; 8 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/labelDataType.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from './dataType'; 2 | 3 | export class LabelDataType extends DataType { 4 | constructor() { 5 | super(); 6 | this.selectedEditor = 'Umbraco.Label'; 7 | this.addPrevalues(''); 8 | } 9 | public addPrevalues(value: string) { 10 | this.preValues = [{ key: 'umbracoDataValueType', value: [value] }]; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cms/models/dataTypes/textBoxDataType.ts: -------------------------------------------------------------------------------- 1 | import { DataType } from './dataType'; 2 | 3 | export class TextBoxDataType extends DataType { 4 | constructor() { 5 | super(); 6 | this.selectedEditor = 'Umbraco.TextBox'; 7 | this.addPrevalues(8); 8 | } 9 | public addPrevalues(maxChars: number) { 10 | this.preValues = [{ key: 'maxChars', value: maxChars }]; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cms/models/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dataTypes'; 2 | export * from './properties'; 3 | export { Template } from './template'; 4 | export { CmsDocumentType } from './cmsDocumentType'; 5 | -------------------------------------------------------------------------------- /src/cms/models/partialViewMacros/partialViewMacro.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Used to generate a new PartialViewMacro 3 | */ 4 | export class PartialViewMacro { 5 | public name = ''; 6 | public content = ''; 7 | public fileType = 'partialViewMacros'; 8 | public notifications = []; 9 | public path = null; 10 | public id = 0; 11 | public snippet = null; 12 | public virtualPath = '/Views/MacroPartials/'; 13 | } 14 | -------------------------------------------------------------------------------- /src/cms/models/properties/baseProperty.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Creates a property object used in document types etc 3 | * 4 | * @param {string} name Name of the property 5 | * @param {string} alias Optional alias of the property 6 | */ 7 | export class BaseProperty { 8 | public id: string; 9 | public alias: string; 10 | public name: string; 11 | constructor(name: string, alias?: string) { 12 | this.alias = alias; 13 | this.name = name; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/cms/models/properties/dropDownProperty.ts: -------------------------------------------------------------------------------- 1 | import { BaseProperty } from './baseProperty'; 2 | 3 | /** 4 | * @param {string} name Property name 5 | * @param {string} alias Property alias 6 | * @param {boolean} multiSelect Bool if Dropdown values can be multi selected 7 | * @param {string[]} values Optional string array of values in the dropdown 8 | */ 9 | export class DropDownProperty extends BaseProperty { 10 | public values: string[]; 11 | public multiSelect: boolean; 12 | constructor(name: string, alias: string, multiSelect = false, values?: string[]) { 13 | super(name, alias); 14 | this.values = values; 15 | this.multiSelect = multiSelect; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/cms/models/properties/formPickerProperty.ts: -------------------------------------------------------------------------------- 1 | import { BaseProperty } from './baseProperty'; 2 | 3 | /** 4 | * @param {string} name Property name 5 | * @param {string} alias Property alias 6 | * @param {string} value Property value of form picker - this stores a UUID of the picked form ID/key 7 | * @param {string[]} allowedFormIds Optional string array of UUIDs of form ID/keys that are allowed to be picked 8 | */ 9 | export class FormPickerProperty extends BaseProperty { 10 | allowedFormIds: string[]; 11 | value: string; 12 | constructor(name: string, alias: string, value: string, allowedFormIds?: string[]) { 13 | super(name, alias); 14 | this.allowedFormIds = allowedFormIds; 15 | this.value = value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/cms/models/properties/index.ts: -------------------------------------------------------------------------------- 1 | export { TextBoxProperty } from './textBoxProperty'; 2 | export { FormPickerProperty } from './formPickerProperty'; 3 | export { DropDownProperty } from './dropDownProperty'; 4 | -------------------------------------------------------------------------------- /src/cms/models/properties/textBoxProperty.ts: -------------------------------------------------------------------------------- 1 | import { BaseProperty } from './baseProperty'; 2 | 3 | export class TextBoxProperty extends BaseProperty { 4 | public value: string; 5 | public maxChars: number; 6 | constructor(name: string, alias: string, maxChars: number, value?: string) { 7 | super(name, alias); 8 | this.value = value; 9 | this.maxChars = maxChars; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/cms/models/template.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | import camelize from 'camelize'; 3 | 4 | /** 5 | * Used to generate a new template 6 | * Will generate name, key and alias and virtualPath for view as random UUID 7 | * 8 | */ 9 | export class Template { 10 | public id = 0; 11 | public name: string = faker.random.uuid(); 12 | public key: string = faker.random.uuid(); 13 | public alias: string = 'a' + camelize(name); 14 | public virtualPath: string = '/Views/' + this.alias + '.cshtml'; 15 | public content = 16 | '@inherits Umbraco.Web.Mvc.UmbracoViewPage\r\n@{\r\n\tLayout = null;\r\n}\r\n\r\n@* the fun starts here *@\r\n\r\n'; 17 | public masterTemplateAlias: string = null; 18 | public path = '-1'; 19 | public isMasterTemplate = false; 20 | public notifications = null; 21 | } 22 | -------------------------------------------------------------------------------- /src/cms/templates/formPickerTemplate.ts: -------------------------------------------------------------------------------- 1 | import { AliasHelper } from '../../helpers/aliasHelper'; 2 | 3 | export class FormPickerTemplate { 4 | /** 5 | * Generates a HTML Razor View to use with Umbraco Forms. 6 | * Adds the Umbraco Forms Macro to the template with the 7 | * 8 | * @param {string} formPickerModel Doctype Property Name that contains the Form Picker 9 | * @param {string} model Name of model to use in HTML Razor View template. Default value is empty string 10 | * @param {{name:string;alias:string}[]} properties Optional array of objects containing `name` and `alias` which will use to print out the Document type property values in the view 11 | * @returns string A basic HTML Razor view with Umbraco Forms macro added to the page, with the correct model for the doctype and prints out values for each property 12 | */ 13 | public get(formPickerModel: string, model = '', properties?: { name: string; alias: string }[]): string { 14 | if (model.length > 0) model = `<${AliasHelper.capitalize(model)}>`; 15 | let template = `@inherits Umbraco.Web.Mvc.UmbracoViewPage${model}\n 16 | @using ContentModels = Umbraco.Web.PublishedModels;\n 17 | @{\n 18 | \tLayout = null;\n 19 | }\n 20 | \n 21 | \t\n 22 | \t\t\n 23 | \t\t\n 24 | \t\t\n 25 | \t\n 26 | \t\n`; 27 | properties?.forEach((property) => { 28 | template += `@Model.Value("${property.alias}")\n`; 29 | }); 30 | template += `\t\t@Umbraco.RenderMacro("renderUmbracoForm", new {FormGuid=Model.${formPickerModel}.ToString(), FormTheme="", ExcludeScripts="0"})`; 31 | template += ` \t\n 32 | \n `; 33 | return template; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/cms/templates/index.ts: -------------------------------------------------------------------------------- 1 | export { FormPickerTemplate } from './formPickerTemplate'; 2 | export { MinimalTemplate } from './minimalTemplate'; 3 | -------------------------------------------------------------------------------- /src/cms/templates/minimalTemplate.ts: -------------------------------------------------------------------------------- 1 | import { AliasHelper } from '../../helpers/aliasHelper'; 2 | 3 | export class MinimalTemplate { 4 | /** 5 | * Generates a HTML string for a basic HTML Razor view template 6 | * 7 | * @param {string} model Name of model to use in HTML Razor View template. Default value is empty string 8 | * @param {{name:string;alias:string}[]} properties Optional array of objects containing `name` and `alias` which will use to print out the Document type property values in the view 9 | * @returns string A basic HTML Razor view with the correct model for the doctype and prints out values for each property 10 | */ 11 | public get(model = '', properties?: { name: string; alias: string }[]): string { 12 | if (model.length > 0) model = `<${AliasHelper.capitalize(model)}>`; 13 | let template = `@inherits Umbraco.Web.Mvc.UmbracoViewPage${model} 14 | @{ 15 | Layout = null; 16 | } 17 | `; 18 | if (properties?.length > 0) { 19 | properties.forEach((property) => { 20 | template += `@Model.Value("${property.alias}")\n`; 21 | }); 22 | } 23 | 24 | return template; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cypress/commands/commandBase.ts: -------------------------------------------------------------------------------- 1 | export default class CommandBase { 2 | _commandName; 3 | _relativeBackOfficePath; 4 | _cy; 5 | _cypress; 6 | 7 | get commandName() { 8 | return this._commandName; 9 | } 10 | set commandName(commandName) { 11 | this._commandName = commandName; 12 | } 13 | get relativeBackOfficePath() { 14 | return this._relativeBackOfficePath; 15 | } 16 | get cy() { 17 | if (typeof this._cy !== 'undefined') { 18 | return this._cy; 19 | } 20 | return cy; 21 | } 22 | 23 | get cypress() { 24 | if (typeof this._cypress !== 'undefined') { 25 | return this._cypress; 26 | } 27 | return Cypress; 28 | } 29 | 30 | constructor(relativeBackOfficePath, cy?, cypress?) { 31 | this._relativeBackOfficePath = relativeBackOfficePath; 32 | this._cy = cy; 33 | this._cypress = cypress; 34 | } 35 | 36 | method(a, b, c, d, e, f, g) { 37 | throw new Error('You have to implement the method()'); 38 | } 39 | getCommand() { 40 | return { 41 | name: this.commandName, 42 | method: (a, b, c, d, e, f, g) => { 43 | this.method(a, b, c, d, e, f, g); 44 | }, 45 | }; 46 | } 47 | registerCommand() { 48 | this.cypress.Commands.add(this.commandName, (a, b, c, d, e, f, g) => { 49 | this.method(a, b, c, d, e, f, g); 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/cypress/commands/cycleHackWorkaroundForPureLiveIssue.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class CycleHackWorkaroundForPureLiveIssue extends CommandBase { 4 | commandName = 'cycleHackWorkaroundForPureLiveIssue'; 5 | 6 | method() { 7 | const cy = this.cy; 8 | 9 | const method = 'GET'; 10 | const url = '/people'; // Nasty hack - this endpoint right now triggers a purelive reset 11 | 12 | return cy 13 | .server() 14 | .route(method, url) 15 | .as('cycleHackWorkaroundForPureLiveIssue') 16 | .window() 17 | .then((win) => { 18 | const xhr = new win.XMLHttpRequest(); 19 | xhr.open(method, url); 20 | xhr.send(); 21 | }) 22 | .wait('@cycleHackWorkaroundForPureLiveIssue', { requestTimeout: 30000 }) 23 | .wait(4000); // We know the app restart is delayed 1000 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/cypress/commands/dataUmb.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | export default class DataUmb extends CommandBase { 3 | commandName = 'dataUmb'; 4 | method(value: string, child?: string) { 5 | if (child !== undefined) return cy.get(`[data-umb=${value}] ${child}`); 6 | else return cy.get(`[data-umb=${value}]`); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/cypress/commands/dataUmbScope.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | export default class DataUmbScope extends CommandBase { 3 | commandName = 'dataUmbScope'; 4 | method(value: string, child?: string) { 5 | const element = child !== undefined ? cy.dataUmb(value, child) : cy.dataUmb(value); 6 | return element.then(($el) => cy.getAngular().then((ng) => ng.element($el).scope())); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteAllContent.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteAllContent extends CommandBase { 5 | commandName = 'deleteAllContent'; 6 | 7 | method() { 8 | const cy = this.cy; 9 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | cy.request({ 11 | method: 'GET', 12 | url: `${this.relativeBackOfficePath}/backoffice/UmbracoTrees/ApplicationTree/GetApplicationTrees?application=content&tree=&use=main`, 13 | headers: { 14 | 'X-UMB-XSRF-TOKEN': token.value, 15 | }, 16 | }).then((response) => { 17 | const content = JsonHelper.getBody(response); 18 | for (const child of content.children) { 19 | if (child.id > 0) { 20 | cy.deleteContentById(child.id); 21 | } 22 | } 23 | return; 24 | }); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteAllDataSources.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteAllDataSources extends CommandBase { 5 | commandName = 'deleteAllDataSources'; 6 | 7 | method() { 8 | const cy = this.cy; 9 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | return cy 11 | .request({ 12 | method: 'GET', 13 | url: `${this.relativeBackOfficePath}/backoffice/UmbracoForms/DataSourceTree/GetNodes?id=-1&application=forms&tree=&use=main&culture=`, 14 | headers: { 15 | 'X-UMB-XSRF-TOKEN': token.value, 16 | }, 17 | }) 18 | .then((response) => { 19 | const dataSources = JsonHelper.getBody(response); 20 | 21 | for (const datasource of dataSources) { 22 | cy.deleteDataSourceByGuId(datasource.id); 23 | } 24 | return; 25 | }); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteAllForms.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteAllForms extends CommandBase { 5 | commandName = 'deleteAllForms'; 6 | 7 | method() { 8 | const cy = this.cy; 9 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | return cy 11 | .request({ 12 | method: 'GET', 13 | url: 14 | this.relativeBackOfficePath + 15 | '/backoffice/UmbracoForms/FormTree/GetNodes?id=-1&application=forms&tree=&use=main&culture=', 16 | headers: { 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | }) 20 | .then((response) => { 21 | const forms = JsonHelper.getBody(response); 22 | 23 | for (const form of forms) { 24 | cy.deleteFormByGuid(form.id); 25 | } 26 | return; 27 | }); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteAllPreValues.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteAllPreValues extends CommandBase { 5 | commandName = 'deleteAllPreValues'; 6 | 7 | method() { 8 | const cy = this.cy; 9 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | return cy 11 | .request({ 12 | method: 'GET', 13 | url: `${this.relativeBackOfficePath}/backoffice/UmbracoForms/PreValueSourceTree/GetNodes?id=-1&application=forms&tree=&use=main&culture=`, 14 | headers: { 15 | 'X-UMB-XSRF-TOKEN': token.value, 16 | }, 17 | }) 18 | .then((response) => { 19 | const preValueSources = JsonHelper.getBody(response); 20 | 21 | for (const preValueSource of preValueSources) { 22 | cy.deletePreValueSourceByGuId(preValueSource.id); 23 | } 24 | return; 25 | }); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteContentById.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class DeleteContentByIid extends CommandBase { 4 | commandName = 'deleteContentById'; 5 | 6 | method(id) { 7 | const cy = this.cy; 8 | 9 | if (id == null) { 10 | return; 11 | } 12 | 13 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 14 | return cy 15 | .request({ 16 | method: 'DELETE', 17 | url: `${this.relativeBackOfficePath}/backoffice/UmbracoApi/Content/DeleteById?id=${id}`, 18 | json: true, 19 | headers: { 20 | Accept: 'application/json', 21 | 'X-UMB-XSRF-TOKEN': token.value, 22 | }, 23 | }) 24 | .then((resp) => { 25 | return resp; 26 | }); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteDataSourceByGuid.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class DeleteDataSourceByGuid extends CommandBase { 4 | commandName = 'deleteDataSourceByGuId'; 5 | 6 | method(guid) { 7 | const cy = this.cy; 8 | 9 | if (guid == null) { 10 | return; 11 | } 12 | 13 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 14 | return cy 15 | .request({ 16 | method: 'DELETE', 17 | url: `${this.relativeBackOfficePath}/backoffice/UmbracoForms/DataSource/DeleteByGuid?guid=${guid}`, 18 | json: true, 19 | headers: { 20 | Accept: 'application/json', 21 | 'X-UMB-XSRF-TOKEN': token.value, 22 | }, 23 | }) 24 | .then((resp) => { 25 | return resp; 26 | }); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteDataTypeById.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteDataTypeById extends CommandBase { 5 | commandName = 'deleteDataTypeById'; 6 | method(id) { 7 | const cy = this.cy; 8 | 9 | if (id == null) { 10 | return; 11 | } 12 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 13 | return cy 14 | .request({ 15 | method: 'POST', 16 | url: this.relativeBackOfficePath + '/backoffice/UmbracoApi/DataType/DeleteById?id=' + id, 17 | headers: { 18 | contentType: 'application/json', 19 | 'X-UMB-XSRF-TOKEN': token.value, 20 | }, 21 | }) 22 | .then((response) => { 23 | return response; 24 | }); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteDataTypesByNamePrefix.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteDataTypesByNamePrefix extends CommandBase { 5 | commandName = 'deleteDataTypesByNamePrefix'; 6 | 7 | method(prefix: string) { 8 | const cy = this.cy; 9 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | return cy 11 | .request({ 12 | method: 'GET', 13 | url: 14 | this.relativeBackOfficePath + 15 | '/backoffice/UmbracoTrees/DataTypeTree/GetNodes?id=-1&application=settings&tree=&use=main&culture=', 16 | headers: { 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | }) 20 | .then((response) => { 21 | const items = JsonHelper.getBody(response); 22 | 23 | for (const item of items) { 24 | if (item.name.startsWith(prefix) || item.name.startsWith(prefix.toLowerCase())) { 25 | cy.deleteDataTypeById(item.id); 26 | } 27 | } 28 | return; 29 | }); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteDocumentType.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteDocumentType extends CommandBase { 5 | commandName = 'deleteDocumentType'; 6 | 7 | method(id) { 8 | const cy = this.cy; 9 | 10 | if (id == null) { 11 | return; 12 | } 13 | 14 | if (typeof id === 'string' || id instanceof String) { 15 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 16 | return cy 17 | .request({ 18 | method: 'GET', 19 | url: this.relativeBackOfficePath + '/backoffice/UmbracoApi/ContentType/GetAll', 20 | headers: { 21 | Accept: 'application/json', 22 | 'X-UMB-XSRF-TOKEN': token.value, 23 | }, 24 | }) 25 | .then((response) => { 26 | const documentTypes = JsonHelper.getBody(response); 27 | for (const documentType of documentTypes) { 28 | if (documentType.alias === id || documentType.key === id) { 29 | return cy.deleteDocumentTypeById(documentType.id); 30 | } 31 | } 32 | }); 33 | }); 34 | } else { 35 | // assume int 36 | return cy.deleteDocumentTypeById(id); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteDocumentTypeById.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteDocumentTypeById extends CommandBase { 5 | commandName = 'deleteDocumentTypeById'; 6 | 7 | method(id) { 8 | const cy = this.cy; 9 | 10 | if (id == null) { 11 | return; 12 | } 13 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 14 | return cy 15 | .request({ 16 | method: 'DELETE', 17 | url: this.relativeBackOfficePath + '/backoffice/UmbracoApi/ContentType/DeleteById?id=' + id, 18 | headers: { 19 | accept: 'application/json', 20 | 'X-UMB-XSRF-TOKEN': token.value, 21 | }, 22 | }) 23 | .then((response) => { 24 | return response; 25 | }); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteDocumentTypesByNamePrefix.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteDocumentTypesByNamePrefix extends CommandBase { 5 | commandName = 'deleteDocumentTypesByNamePrefix'; 6 | 7 | method(prefix) { 8 | const cy = this.cy; 9 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | return cy 11 | .request({ 12 | method: 'GET', 13 | url: 14 | this.relativeBackOfficePath + 15 | '/backoffice/UmbracoTrees/ContentTypeTree/GetNodes?id=-1&application=settings&tree=&use=main&culture=', 16 | headers: { 17 | Accept: 'application/json', 18 | 'X-UMB-XSRF-TOKEN': token.value, 19 | }, 20 | }) 21 | .then((response) => { 22 | const items = JsonHelper.getBody(response); 23 | for (const item of items) { 24 | if (item.name?.startsWith(prefix)) cy.deleteDocumentTypeById(item.id); 25 | } 26 | return; 27 | }); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteForm.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteForm extends CommandBase { 5 | commandName = 'deleteForm'; 6 | 7 | method(id) { 8 | const cy = this.cy; 9 | 10 | if (id == null) { 11 | return; 12 | } 13 | 14 | if (typeof id === 'string' || id instanceof String) { 15 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 16 | cy.request({ 17 | method: 'GET', 18 | url: 19 | this.relativeBackOfficePath + 20 | '/backoffice/UmbracoForms/FormTree/GetNodes?id=-1&application=forms&tree=&use=main&culture=', 21 | headers: { 22 | Accept: 'application/json', 23 | 'X-UMB-XSRF-TOKEN': token.value, 24 | }, 25 | }).then((response) => { 26 | const forms = JsonHelper.getBody(response); 27 | for (const form of forms) { 28 | if (form.name === id || form.key === id) { 29 | cy.deleteFormByGuid(forms.id); 30 | break; 31 | } 32 | } 33 | }); 34 | }); 35 | } else { 36 | // assume guid 37 | cy.deleteFormByGuid(id); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteFormByGuid.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class DeleteFormByGuid extends CommandBase { 4 | commandName = 'deleteFormByGuid'; 5 | 6 | method(guid) { 7 | const cy = this.cy; 8 | 9 | if (guid == null) { 10 | return; 11 | } 12 | 13 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 14 | return cy 15 | .request({ 16 | method: 'DELETE', 17 | url: this.relativeBackOfficePath + '/backoffice/UmbracoForms/Form/DeleteByGuid?guid=' + guid, 18 | json: true, 19 | headers: { 20 | Accept: 'application/json', 21 | 'X-UMB-XSRF-TOKEN': token.value, 22 | }, 23 | }) 24 | .then((resp) => { 25 | return resp; 26 | }); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteFormsByNamePrefix.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteFormsByNamePrefix extends CommandBase { 5 | commandName = 'deleteFormsByNamePrefix'; 6 | 7 | method(prefix) { 8 | const cy = this.cy; 9 | 10 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | return cy 12 | .request({ 13 | method: 'GET', 14 | url: 15 | this.relativeBackOfficePath + 16 | '/backoffice/UmbracoForms/FormTree/GetNodes?id=-1&application=forms&tree=&use=main&culture=', 17 | headers: { 18 | Accept: 'application/json', 19 | 'X-UMB-XSRF-TOKEN': token.value, 20 | }, 21 | }) 22 | .then((response) => { 23 | const items = JsonHelper.getBody(response); 24 | for (const item of items) { 25 | if (item.name?.startsWith(prefix)) { 26 | cy.deleteFormByGuid(item.id); 27 | } 28 | } 29 | return; 30 | }); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/cypress/commands/deletePreValueSourceByGuid.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class DeletePreValueSourceByGuid extends CommandBase { 4 | commandName = 'deletePreValueSourceByGuId'; 5 | 6 | method(guid) { 7 | const cy = this.cy; 8 | 9 | if (guid == null) { 10 | return; 11 | } 12 | 13 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 14 | return cy 15 | .request({ 16 | method: 'DELETE', 17 | url: `${this.relativeBackOfficePath}/backoffice/UmbracoForms/PreValueSource/DeleteByGuid?guid=${guid}`, 18 | json: true, 19 | headers: { 20 | Accept: 'application/json', 21 | 'X-UMB-XSRF-TOKEN': token.value, 22 | }, 23 | }) 24 | .then((resp) => { 25 | return resp; 26 | }); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteTemplateById.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteTemplateById extends CommandBase { 5 | commandName = 'deleteTemplateById'; 6 | 7 | method(id) { 8 | const cy = this.cy; 9 | if (id == null) { 10 | return; 11 | } 12 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 13 | cy.request({ 14 | method: 'POST', 15 | url: this.relativeBackOfficePath + '/backoffice/UmbracoApi/Template/DeleteById?id=' + id, 16 | headers: { 17 | contentType: 'application/json', 18 | 'X-UMB-XSRF-TOKEN': token.value, 19 | }, 20 | }).then((response) => { 21 | return response; 22 | }); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/cypress/commands/deleteTemplatesByNamePrefix.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class DeleteTemplatesByNamePrefix extends CommandBase { 5 | commandName = 'deleteTemplatesByNamePrefix'; 6 | 7 | method(prefix) { 8 | const cy = this.cy; 9 | 10 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: 14 | this.relativeBackOfficePath + 15 | '/backoffice/UmbracoTrees/TemplatesTree/GetNodes?id=-1&application=settings&tree=&use=main&culture=', 16 | headers: { 17 | Accept: 'application/json', 18 | 'X-UMB-XSRF-TOKEN': token.value, 19 | }, 20 | }).then((response) => { 21 | const items = JsonHelper.getBody(response); 22 | 23 | for (const item of items) { 24 | if (item.name?.startsWith(prefix)) { 25 | cy.deleteTemplateById(item.id); 26 | } 27 | } 28 | return; 29 | }); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/cypress/commands/editTemplate.ts: -------------------------------------------------------------------------------- 1 | import { JsonHelper } from '../../helpers/jsonHelper'; 2 | import CommandBase from './commandBase'; 3 | 4 | export default class UmbracoEditTemplate extends CommandBase { 5 | _commandName = 'editTemplate'; 6 | 7 | method(name, content) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | // Get a list of all templates 12 | cy.request({ 13 | method: 'GET', 14 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/TemplatesTree/GetNodes?id=-1', 15 | followRedirect: true, 16 | headers: { 17 | Accept: 'application/json', 18 | 'X-UMB-XSRF-TOKEN': token.value, 19 | }, 20 | log: false, 21 | // Find template by name 22 | }).then((resonse) => { 23 | const searchBody = JsonHelper.getBody(resonse); 24 | if (searchBody.length > 0) { 25 | let templateId = null; 26 | for (const sb of searchBody) { 27 | if (sb.name === name) { 28 | templateId = sb.id; 29 | } 30 | } 31 | 32 | if (templateId !== null) { 33 | // Template found, find details of that template 34 | cy.request({ 35 | method: 'GET', 36 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/Template/GetById?id=' + templateId, 37 | followRedirect: false, 38 | headers: { 39 | Accept: 'application/json', 40 | 'X-UMB-XSRF-TOKEN': token.value, 41 | }, 42 | }).then((resp) => { 43 | // Change the content and save that template 44 | const template = JsonHelper.getBody(resp); 45 | template.content = content; 46 | return cy.saveTemplate(template); 47 | }); 48 | } 49 | } 50 | }); 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/cypress/commands/getAngular.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | export default class GetAngular extends CommandBase { 3 | commandName = 'getAngular'; 4 | method() { 5 | return cy.window().its('angular'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/cypress/commands/postFile.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class PostFile extends CommandBase { 5 | commandName = 'postFile'; 6 | method(fileName: string, url: string) { 7 | const cy = this.cy; 8 | const method = 'POST'; 9 | url = this.relativeBackOfficePath + url; 10 | const formData = new FormData(); 11 | 12 | cy.fixture(fileName, 'base64').then((fileFixture) => { 13 | const blob = Cypress.Blob.base64StringToBlob(fileFixture); 14 | // @ts-ignore 15 | const testFile = new File([blob], fileName); 16 | formData.append('file', testFile); 17 | cy.getCookie('UMB-XSRF-TOKEN').then((token) => { 18 | cy.server({ 19 | ignore: (request) => { 20 | return; 21 | }, 22 | }); 23 | cy.route(method, url).as('postAdd'); 24 | cy.window() 25 | .then((win) => { 26 | const xhr = new win.XMLHttpRequest(); 27 | xhr.open(method, url); 28 | xhr.setRequestHeader('X-UMB-XSRF-TOKEN', token.value); 29 | xhr.send(formData); 30 | }) 31 | .wait('@postAdd') 32 | .then((res) => { 33 | return JsonHelper.getBody(res.response); 34 | }); 35 | }); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/cypress/commands/postRequest.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class PostRequest extends CommandBase { 5 | commandName = 'postRequest'; 6 | method(url: string, payload: any) { 7 | const cy = this.cy; 8 | const method = 'POST'; 9 | url = this.relativeBackOfficePath + url; 10 | 11 | cy.getCookie('UMB-XSRF-TOKEN').then((token) => { 12 | cy.server({ 13 | ignore: (request) => { 14 | return; 15 | }, 16 | }); 17 | cy.route(method, url).as('postRequest'); 18 | cy.window() 19 | .then((win) => { 20 | const xhr = new win.XMLHttpRequest(); 21 | xhr.open(method, url); 22 | xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); 23 | xhr.setRequestHeader('X-UMB-XSRF-TOKEN', token.value); 24 | xhr.send(JSON.stringify(payload)); 25 | }) 26 | .wait('@postRequest') 27 | .then((res) => { 28 | return JsonHelper.getBody(res.response); 29 | }); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/cypress/commands/saveCodeFile.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveCodeFile extends CommandBase { 4 | commandName = 'saveCodeFile'; 5 | 6 | method(codeFile) { 7 | const cy = this.cy; 8 | 9 | if (codeFile == null) { 10 | return; 11 | } 12 | 13 | return cy.umbracoApiRequest( 14 | this.relativeBackOfficePath + '/backoffice/UmbracoApi/CodeFile/PostSave', 15 | 'POST', 16 | codeFile, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/saveContent.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class SaveContent extends CommandBase { 5 | commandName = 'saveContent'; 6 | 7 | method(content) { 8 | const cy = this.cy; 9 | 10 | if (content == null) { 11 | return; 12 | } 13 | 14 | const method = 'POST'; 15 | const url = this.relativeBackOfficePath + '/backoffice/UmbracoApi/Content/PostSave'; 16 | const formData = new FormData(); 17 | formData.append('contentItem', JSON.stringify(content)); 18 | return cy.getCookie('UMB-XSRF-TOKEN').then((token) => { 19 | cy.server({ 20 | ignore: (request) => { 21 | return; 22 | }, 23 | }); 24 | cy.route(method, url).as('postSave'); 25 | cy.window() 26 | .then((win) => { 27 | const xhr = new win.XMLHttpRequest(); 28 | xhr.open(method, url); 29 | xhr.setRequestHeader('X-UMB-XSRF-TOKEN', token.value); 30 | xhr.send(formData); 31 | }) 32 | .wait('@postSave') 33 | .then((res) => { 34 | return JsonHelper.getBody(res.response); 35 | }); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/cypress/commands/saveDataType.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveDataType extends CommandBase { 4 | commandName = 'saveDataType'; 5 | 6 | method(dataType) { 7 | const cy = this.cy; 8 | 9 | if (dataType == null) { 10 | return; 11 | } 12 | 13 | return cy.umbracoApiRequest( 14 | this.relativeBackOfficePath + '/backoffice/UmbracoApi/DataType/PostSave', 15 | 'POST', 16 | dataType, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/saveDocumentType.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveDocumentType extends CommandBase { 4 | commandName = 'saveDocumentType'; 5 | 6 | method(docType) { 7 | const cy = this.cy; 8 | 9 | if (docType == null) { 10 | return; 11 | } 12 | 13 | return cy.umbracoApiRequest( 14 | this.relativeBackOfficePath + '/backoffice/UmbracoApi/ContentType/PostSave', 15 | 'POST', 16 | docType, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/saveFolder.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class SaveFolder extends CommandBase { 5 | commandName = 'saveFolder'; 6 | 7 | method(section, name) { 8 | const cy = this.cy; 9 | 10 | if (section == null) { 11 | return; 12 | } 13 | 14 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 15 | cy.request({ 16 | method: 'POST', 17 | url: 18 | this.relativeBackOfficePath + 19 | '/backoffice/UmbracoApi/CodeFile/PostCreateContainer?type=' + 20 | section + 21 | '&parentId=-1&name=' + 22 | name, 23 | timeout: 90000, 24 | headers: { 25 | Accept: 'application/json, text/plain, */*', 26 | 'X-UMB-XSRF-TOKEN': token.value, 27 | }, 28 | }).then((response) => { 29 | return JsonHelper.getBody(response); 30 | }); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/cypress/commands/saveForm.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveForm extends CommandBase { 4 | commandName = 'saveForm'; 5 | 6 | method(form) { 7 | const cy = this.cy; 8 | 9 | if (form == null) { 10 | return; 11 | } 12 | 13 | return cy.umbracoApiRequest(this.relativeBackOfficePath + '/backoffice/UmbracoForms/Form/SaveForm', 'POST', form); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/cypress/commands/saveMacro.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveMacro extends CommandBase { 4 | commandName = 'saveMacro'; 5 | 6 | method(name: string) { 7 | const cy = this.cy; 8 | if (name.length == 0) { 9 | return; 10 | } 11 | 12 | return cy.umbracoApiRequest( 13 | this.relativeBackOfficePath + '/backoffice/UmbracoApi/Macros/Create?name=' + name, 14 | 'POST', 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/cypress/commands/saveMedia.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from "./commandBase"; 2 | import {JsonHelper} from "../../helpers/jsonHelper"; 3 | 4 | export default class SaveMedia extends CommandBase { 5 | commandName = 'saveMedia'; 6 | 7 | method(media, file) { 8 | const cy = this.cy; 9 | 10 | if (media == null) { 11 | return; 12 | } 13 | 14 | const method = 'POST'; 15 | const url = this.relativeBackOfficePath + '/backoffice/UmbracoApi/Media/PostSave'; 16 | const formData = new FormData(); 17 | formData.append('contentItem', JSON.stringify(media)); 18 | 19 | if (file != null) { 20 | formData.append('file_umbracoFile__', file) 21 | } 22 | 23 | return cy.getCookie('UMB-XSRF-TOKEN').then((token) => { 24 | cy.server({ 25 | ignore: (request) => { 26 | return; 27 | }, 28 | }); 29 | cy.route(method, url).as('postSave'); 30 | cy.window() 31 | .then((win) => { 32 | const xhr = new win.XMLHttpRequest(); 33 | xhr.open(method, url); 34 | xhr.setRequestHeader('X-UMB-XSRF-TOKEN', token.value); 35 | xhr.send(formData); 36 | }) 37 | .wait('@postSave') 38 | .then((res) => { 39 | return JsonHelper.getBody(res.response); 40 | }); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/cypress/commands/savePartialView.ts: -------------------------------------------------------------------------------- 1 | import SaveCodeFile from './saveCodeFile'; 2 | 3 | export default class SavePartialView extends SaveCodeFile { 4 | commandName = 'savePartialView'; 5 | } 6 | -------------------------------------------------------------------------------- /src/cypress/commands/savePartialViewMacro.ts: -------------------------------------------------------------------------------- 1 | import SaveCodeFile from './saveCodeFile'; 2 | 3 | export default class SavePartialViewMacro extends SaveCodeFile { 4 | commandName = 'savePartialViewMacro'; 5 | } 6 | -------------------------------------------------------------------------------- /src/cypress/commands/saveScript.ts: -------------------------------------------------------------------------------- 1 | import SaveCodeFile from './saveCodeFile'; 2 | 3 | export default class SaveScript extends SaveCodeFile { 4 | commandName = 'saveScript'; 5 | } 6 | -------------------------------------------------------------------------------- /src/cypress/commands/saveStylesheet.ts: -------------------------------------------------------------------------------- 1 | import SaveCodeFile from './saveCodeFile'; 2 | 3 | export default class SaveStylesheet extends SaveCodeFile { 4 | commandName = 'saveStylesheet'; 5 | } 6 | -------------------------------------------------------------------------------- /src/cypress/commands/saveTemplate.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveTemplate extends CommandBase { 4 | commandName = 'saveTemplate'; 5 | 6 | method(template) { 7 | const cy = this.cy; 8 | 9 | if (template == null) { 10 | return; 11 | } 12 | 13 | return cy.umbracoApiRequest( 14 | this.relativeBackOfficePath + '/backoffice/UmbracoApi/Template/PostSave', 15 | 'POST', 16 | template, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/saveUser.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveUser extends CommandBase { 4 | commandName = 'saveUser'; 5 | 6 | method(user) { 7 | const cy = this.cy; 8 | 9 | if (user == null) { 10 | return; 11 | } 12 | 13 | return cy.umbracoApiRequest( 14 | this.relativeBackOfficePath + '/backoffice/umbracoapi/users/PostCreateUser', 15 | 'POST', 16 | user, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/saveUserGroup.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class SaveUserGroup extends CommandBase { 4 | commandName = 'saveUserGroup'; 5 | 6 | method(userGroup) { 7 | const cy = this.cy; 8 | 9 | if (userGroup == null) { 10 | return; 11 | } 12 | 13 | return cy.umbracoApiRequest( 14 | this.relativeBackOfficePath + '/backoffice/umbracoapi/usergroups/PostSaveUserGroup', 15 | 'POST', 16 | userGroup, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoApiRequest.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoApiRequest extends CommandBase { 5 | commandName = 'umbracoApiRequest'; 6 | 7 | method(url, method, body) { 8 | const cy = this.cy; 9 | 10 | if (url == null || url === '') { 11 | return null; 12 | } 13 | 14 | return cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 15 | cy.request({ 16 | method: method ?? 'GET', 17 | url: url, 18 | body: body, 19 | timeout: 90000, 20 | json: true, 21 | headers: { 22 | Accept: 'application/json', 23 | 'X-UMB-XSRF-TOKEN': token.value, 24 | }, 25 | }).then((response) => { 26 | if (response.isOkStatusCode && response.body != null) { 27 | return JsonHelper.getBody(response); 28 | } 29 | return null; 30 | }); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoButtonByLabelKey.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoButtonByLabelKey extends CommandBase { 4 | _commandName = 'umbracoButtonByLabelKey'; 5 | 6 | method(label) { 7 | const cy = this.cy; 8 | const cypress = this.cypress; 9 | 10 | cypress.log({ 11 | displayName: 'Umbraco Button', 12 | }); 13 | 14 | return cy.get('umb-button[label-key="' + label + '"] button:enabled', { 15 | log: false, 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoContextMenuAction.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoContextMenuAction extends CommandBase { 4 | _commandName = 'umbracoContextMenuAction'; 5 | 6 | method(actionName) { 7 | const cy = this.cy; 8 | const cypress = this.cypress; 9 | 10 | cypress.log({ 11 | displayName: 'Umbraco Context Menu Action', 12 | message: actionName, 13 | }); 14 | 15 | return cy.get('li.umb-action[data-element="' + actionName + '"]', { 16 | log: false, 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoCreateDocTypeWithContent.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { DocumentTypeBuilder } from '../../cms/builders/documentTypes/documentTypeBuilder'; 3 | import { ContentBuilder } from '../../cms/builders/content/contentBuilder'; 4 | export default class UmbracoCreateDocTypeWithContent extends CommandBase { 5 | _commandName = 'umbracoCreateDocTypeWithContent'; 6 | 7 | method(name, alias, dataTypeBuilder) { 8 | cy.saveDataType(dataTypeBuilder).then((dataType) => { 9 | // Create a document type using the data type 10 | const docType = new DocumentTypeBuilder() 11 | .withName(name) 12 | .withAlias(alias) 13 | .withAllowAsRoot(true) 14 | .withDefaultTemplate(alias) 15 | .addGroup() 16 | .addCustomProperty(dataType['id']) 17 | .withAlias('umbracoTest') 18 | .done() 19 | .done() 20 | .build(); 21 | 22 | cy.saveDocumentType(docType).then((generatedDocType) => { 23 | const contentNode = new ContentBuilder() 24 | .withContentTypeAlias(generatedDocType['alias']) 25 | .addVariant() 26 | .withName(name) 27 | .withSave(true) 28 | .done() 29 | .build(); 30 | 31 | cy.saveContent(contentNode); 32 | }); 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEditorHeaderName.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { AliasHelper } from '../../helpers/aliasHelper'; 3 | 4 | export default class UmbracoEditorHeaderName extends CommandBase { 5 | _commandName = 'umbracoEditorHeaderName'; 6 | 7 | method(typedText) { 8 | const cy = this.cy; 9 | const cypress = this.cypress; 10 | 11 | cypress.log({ 12 | displayName: 'Umbraco Editor Header Name', 13 | }); 14 | 15 | cy.get('#headerName', { log: false }).type(typedText, { timeout: 10000 }).should('have.value', typedText); 16 | 17 | cy.get('.umb-editor-header__name-wrapper').then(($wrapper) => { 18 | if ($wrapper.find('[name="lockedFieldForm"]').length > 0) { 19 | const alias = AliasHelper.toAlias(typedText); 20 | cy.get('input[name="lockedField"]').should('have.value', alias); 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureDataTypeNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureDataTypeNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureDataTypeNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/DataType/GetByName?name=' + name, 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody != null) { 23 | const dataTypeId = searchBody.id; 24 | 25 | if (dataTypeId !== null) { 26 | cy.request({ 27 | method: 'POST', 28 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/DataType/DeleteById?id=' + dataTypeId, 29 | followRedirect: false, 30 | headers: { 31 | ContentType: 'application/json', 32 | 'X-UMB-XSRF-TOKEN': token.value, 33 | }, 34 | }).then((resp) => { 35 | return; 36 | }); 37 | } 38 | } 39 | }); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureDocumentTypeNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureDocumentTypeNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureDocumentTypeNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/ContentTypeTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let documentTypeId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | documentTypeId = sb.id; 27 | } 28 | } 29 | 30 | if (documentTypeId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/ContentType/DeleteById?id=' + documentTypeId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureLanguageNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureLanguageNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureLanguageNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/Language/GetAllLanguages', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let languageId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | languageId = sb.id; 27 | } 28 | } 29 | 30 | if (languageId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/Language/DeleteLanguage?id=' + languageId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureMacroNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureMacroNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureMacroNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/MacrosTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let macroId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | macroId = sb.id; 27 | } 28 | } 29 | 30 | if (macroId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/Macros/DeleteById?id=' + macroId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureMediaTypeNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureMediaTypeNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureMediaTypeNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/MediaTypeTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let mediaTypeId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | mediaTypeId = sb.id; 27 | } 28 | } 29 | 30 | if (mediaTypeId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/MediaType/DeleteById?id=' + mediaTypeId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureMemberEmailNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureMemberEmailNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureMemberEmailNotExists'; 6 | 7 | method(email) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: 14 | this._relativeBackOfficePath + 15 | '/backoffice/UmbracoApi/Member/GetPagedResults?pageNumber=1&pageSize=1&orderBy=Name&orderDirection=Ascending&filter=' + 16 | email, 17 | followRedirect: true, 18 | headers: { 19 | Accept: 'application/json', 20 | 'X-UMB-XSRF-TOKEN': token.value, 21 | }, 22 | log: false, 23 | }).then((response) => { 24 | const searchBody = JsonHelper.getBody(response); 25 | if (searchBody.totalItems >= 1) { 26 | const memberKey = searchBody.items[0].key; 27 | cy.request({ 28 | method: 'POST', 29 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/Member/DeleteByKey?key=' + memberKey, 30 | followRedirect: false, 31 | headers: { 32 | ContentType: 'application/json', 33 | 'X-UMB-XSRF-TOKEN': token.value, 34 | }, 35 | }).then((resp) => { 36 | return; 37 | }); 38 | } 39 | }); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureMemberGroupNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureMemberGroupNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureMemberGroupNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/MemberGroupTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let memberGroupId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | memberGroupId = sb.id; 27 | } 28 | } 29 | 30 | if (memberGroupId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/MemberGroup/DeleteById?id=' + memberGroupId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureMemberTypeNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureMemberTypeNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureMemberTypeNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/MemberType/GetAllTypes', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let memberTypeId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | memberTypeId = sb.id; 27 | } 28 | } 29 | 30 | if (memberTypeId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/MemberType/DeleteById?id=' + memberTypeId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureMultipleDocumentTypeNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoEnsureMultipleDocumentTypeNameNotExists extends CommandBase { 4 | _commandName = 'umbracoEnsureMultipleDocumentTypeNameNotExists'; 5 | method(names) { 6 | names.forEach(function (value) { 7 | cy.umbracoEnsureDocumentTypeNameNotExists(value); 8 | }); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsurePackageNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsurePackageNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsurePackageNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | const relativeBackOfficePath = this._relativeBackOfficePath; 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: relativeBackOfficePath + '/backoffice/umbracoapi/package/GetCreatedPackages', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | searchBody.forEach(function (value){ 24 | if(name == value.name){ 25 | cy.request({ 26 | method: 'POST', 27 | url: 28 | relativeBackOfficePath + '/backoffice/umbracoapi/package/DeleteCreatedPackage?packageId=' + value.id, 29 | followRedirect: false, 30 | headers: { 31 | ContentType: 'application/json', 32 | 'X-UMB-XSRF-TOKEN': token.value, 33 | }, 34 | }); 35 | } 36 | }); 37 | } 38 | }); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsurePartialViewMacroFileNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsurePartialViewMacroFileNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsurePartialViewMacroFileNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/PartialViewMacrosTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let partialViewId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | partialViewId = sb.id; 27 | } 28 | } 29 | 30 | if (partialViewId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: 34 | this._relativeBackOfficePath + 35 | '/backoffice/UmbracoApi/CodeFile/Delete?type=partialViewMacros&virtualPath=' + 36 | partialViewId, 37 | followRedirect: false, 38 | headers: { 39 | ContentType: 'application/json', 40 | 'X-UMB-XSRF-TOKEN': token.value, 41 | }, 42 | }).then((resp) => { 43 | return; 44 | }); 45 | } 46 | } 47 | }); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsurePartialViewNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsurePartialViewNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsurePartialViewNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/PartialViewsTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let partialViewId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | partialViewId = sb.id; 27 | } 28 | } 29 | 30 | if (partialViewId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: 34 | this._relativeBackOfficePath + 35 | '/backoffice/UmbracoApi/CodeFile/Delete?type=partialViews&virtualPath=' + 36 | partialViewId, 37 | followRedirect: false, 38 | headers: { 39 | ContentType: 'application/json', 40 | 'X-UMB-XSRF-TOKEN': token.value, 41 | }, 42 | }).then((resp) => { 43 | return; 44 | }); 45 | } 46 | } 47 | }); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureRelationTypeNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureRelationTypeNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureRelationTypeNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/RelationTypeTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let relationTypeId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | relationTypeId = sb.id; 27 | } 28 | } 29 | 30 | if (relationTypeId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/RelationType/DeleteById?id=' + relationTypeId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureScriptNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureScriptNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureScriptNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/BackOffice/Api/ScriptsTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let partialViewId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | partialViewId = sb.id; 27 | } 28 | } 29 | 30 | if (partialViewId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: 34 | this._relativeBackOfficePath + 35 | '/backoffice/UmbracoApi/CodeFile/Delete?type=scripts&virtualPath=' + 36 | partialViewId, 37 | followRedirect: false, 38 | headers: { 39 | ContentType: 'application/json', 40 | 'X-UMB-XSRF-TOKEN': token.value, 41 | }, 42 | }).then((resp) => { 43 | return; 44 | }); 45 | } 46 | } 47 | }); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureStylesheetNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureStylesheetNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureStylesheetNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/BackOffice/Api/StylesheetsTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let partialViewId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | partialViewId = sb.id; 27 | } 28 | } 29 | 30 | if (partialViewId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: 34 | this._relativeBackOfficePath + 35 | '/backoffice/UmbracoApi/CodeFile/Delete?type=stylesheets&virtualPath=' + 36 | partialViewId, 37 | followRedirect: false, 38 | headers: { 39 | ContentType: 'application/json', 40 | 'X-UMB-XSRF-TOKEN': token.value, 41 | }, 42 | }).then((resp) => { 43 | return; 44 | }); 45 | } 46 | } 47 | }); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureTemplateNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureTemplateNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureTemplateNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: this._relativeBackOfficePath + '/backoffice/UmbracoTrees/TemplatesTree/GetNodes?id=-1', 14 | followRedirect: true, 15 | headers: { 16 | Accept: 'application/json', 17 | 'X-UMB-XSRF-TOKEN': token.value, 18 | }, 19 | log: false, 20 | }).then((response) => { 21 | const searchBody = JsonHelper.getBody(response); 22 | if (searchBody.length > 0) { 23 | let templateId = null; 24 | for (const sb of searchBody) { 25 | if (sb.name === name) { 26 | templateId = sb.id; 27 | } 28 | } 29 | 30 | if (templateId !== null) { 31 | cy.request({ 32 | method: 'POST', 33 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/Template/DeleteById?id=' + templateId, 34 | followRedirect: false, 35 | headers: { 36 | ContentType: 'application/json', 37 | 'X-UMB-XSRF-TOKEN': token.value, 38 | }, 39 | }).then((resp) => { 40 | return; 41 | }); 42 | } 43 | } 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureUserEmailNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureUserEmailNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureUserEmailNotExists'; 6 | 7 | method(email) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: 14 | this._relativeBackOfficePath + 15 | '/backoffice/UmbracoApi/Users/GetPagedUsers?pageNumber=1&pageSize=1&orderBy=Name&orderDirection=Ascending&filter=' + 16 | email, 17 | followRedirect: true, 18 | headers: { 19 | Accept: 'application/json', 20 | 'X-UMB-XSRF-TOKEN': token.value, 21 | }, 22 | log: false, 23 | }).then((response) => { 24 | const searchBody = JsonHelper.getBody(response); 25 | if (searchBody.totalItems >= 1) { 26 | const userId = searchBody.items[0].id; 27 | cy.request({ 28 | method: 'POST', 29 | url: this._relativeBackOfficePath + '/backoffice/UmbracoApi/Users/PostDeleteNonLoggedInUser?id=' + userId, 30 | followRedirect: false, 31 | headers: { 32 | ContentType: 'application/json', 33 | 'X-UMB-XSRF-TOKEN': token.value, 34 | }, 35 | }).then((resp) => { 36 | return; 37 | }); 38 | } 39 | }); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoEnsureUserGroupNameNotExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | export default class UmbracoEnsureUserGroupNameNotExists extends CommandBase { 5 | _commandName = 'umbracoEnsureUserGroupNameNotExists'; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 11 | cy.request({ 12 | method: 'GET', 13 | url: 14 | this._relativeBackOfficePath + '/backoffice/UmbracoApi/UserGroups/GetUserGroups?onlyCurrentUserGroups=false', 15 | followRedirect: true, 16 | headers: { 17 | Accept: 'application/json', 18 | 'X-UMB-XSRF-TOKEN': token.value, 19 | }, 20 | log: false, 21 | }).then((response) => { 22 | const searchBody = JsonHelper.getBody(response); 23 | if (searchBody.length > 0) { 24 | let userGroupId = null; 25 | for (const sb of searchBody) { 26 | if (sb.name === name) { 27 | userGroupId = sb.id; 28 | } 29 | } 30 | 31 | if (userGroupId !== null) { 32 | cy.request({ 33 | method: 'POST', 34 | url: 35 | this._relativeBackOfficePath + 36 | '/backoffice/UmbracoApi/UserGroups/PostDeleteUserGroups?userGroupIds=' + 37 | userGroupId, 38 | followRedirect: false, 39 | headers: { 40 | ContentType: 'application/json', 41 | 'X-UMB-XSRF-TOKEN': token.value, 42 | }, 43 | }).then((resp) => { 44 | return; 45 | }); 46 | } 47 | } 48 | }); 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoErrorNotification.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoErrorNotification extends CommandBase { 4 | _commandName = 'umbracoErrorNotification'; 5 | 6 | method() { 7 | const cy = this.cy; 8 | 9 | cy.get('.umb-notifications__notifications > .alert-error', { 10 | log: false, 11 | timout: 60000, // This is often tested after a long running operation 12 | }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoFileExists.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoFileExists extends CommandBase { 4 | _commandName = 'umbracoFileExists'; 5 | _endPoint; 6 | 7 | method(name) { 8 | const cy = this.cy; 9 | 10 | cy.umbracoApiRequest(this._relativeBackOfficePath + this._endPoint).then((searchBody) => { 11 | if (searchBody.length > 0) { 12 | for (const sb of searchBody) { 13 | if (sb.name === name) { 14 | return true; 15 | } 16 | } 17 | } 18 | return false; 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoGlobalHelp.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoGlobalHelp extends CommandBase { 4 | commandName = 'umbracoGlobalHelp'; 5 | 6 | method() { 7 | const cy = this.cy; 8 | 9 | return cy.get('[data-element="global-help"]'); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoGlobalUser.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoGlobalUser extends CommandBase { 4 | commandName = 'umbracoGlobalUser'; 5 | 6 | method() { 7 | const cy = this.cy; 8 | 9 | return cy.get('[data-element="global-user"]'); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoInstall.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import faker from 'faker'; 3 | 4 | export default class UmbracoInstall extends CommandBase { 5 | _commandName = 'umbracoInstall'; 6 | 7 | method( 8 | username: string = Cypress.env('username'), 9 | password: string = Cypress.env('password'), 10 | connectionString: string = Cypress.env('connectionString'), 11 | ): void { 12 | const cy = this.cy; 13 | return cy.visit(`/install`, { failOnStatusCode: false }).then(() => { 14 | cy.server(); 15 | cy.route('GET', '/install/api/GetSetup').as('getSetup'); 16 | cy.route('POST', '/install/api/PostValidateDatabaseConnection').as('validateDatabase'); 17 | cy.route('GET', '/install/api/GetPackages').as('getPackages'); 18 | cy.wait('@getSetup').then(() => { 19 | cy.get('input[placeholder="Full name"').type(faker.random.word()); 20 | cy.get('input[placeholder="you@example.com"').type(username); 21 | cy.get('input[name="installer.current.model.password"').type(password); 22 | cy.get('.control-customize').click(); 23 | 24 | cy.get('#dbType').select('Custom connection string'); 25 | cy.get('.input-block-level').type(connectionString); 26 | cy.get('form').submit(); 27 | cy.wait('@validateDatabase').then(() => { 28 | cy.wait('@getPackages').then(() => { 29 | cy.get('.btn-link-reverse').click(); 30 | cy.waitUntil(() => cy.getCookie('UMB-XSRF-TOKEN'), { timeout: 2400000, interval: 500 }).then((p) => { 31 | this.cy.log('Umbraco installed'); 32 | return; 33 | }); 34 | }); 35 | }); 36 | }); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoMacroExists.ts: -------------------------------------------------------------------------------- 1 | import UmbracoFileExists from './umbracoFileExists'; 2 | 3 | export default class UmbracoMacroExists extends UmbracoFileExists { 4 | _commandName = 'umbracoMacroExists'; 5 | _endPoint = '/backoffice/UmbracoTrees/MacrosTree/GetNodes?id=-1'; 6 | } 7 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoPartialViewExists.ts: -------------------------------------------------------------------------------- 1 | import UmbracoFileExists from './umbracoFileExists'; 2 | 3 | export default class UmbracoPartialViewExists extends UmbracoFileExists { 4 | _commandName = 'umbracoPartialViewExists'; 5 | _endPoint = '/backoffice/UmbracoTrees/PartialViewsTree/GetNodes?id=-1'; 6 | } 7 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoRefreshContentTree.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoRefreshContentTree extends CommandBase { 4 | _commandName = 'umbracoRefreshContentTree'; 5 | method (){ 6 | // Refresh to update the tree 7 | cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); 8 | cy.umbracoContextMenuAction("action-refreshNode").click(); 9 | // We have to wait in case the execution is slow, otherwise we'll try and click the item before it appears in the UI 10 | cy.get('.umb-tree-item__inner').should('exist', {timeout: 10000}); 11 | } 12 | } -------------------------------------------------------------------------------- /src/cypress/commands/umbracoScriptExists.ts: -------------------------------------------------------------------------------- 1 | import UmbracoFileExists from './umbracoFileExists'; 2 | 3 | export default class UmbracoScriptExists extends UmbracoFileExists { 4 | _commandName = 'umbracoScriptExists'; 5 | _endPoint = '/BackOffice/Api/ScriptsTree/GetNodes?id=-1'; 6 | } 7 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoSection.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoSection extends CommandBase { 4 | _commandName = 'umbracoSection'; 5 | 6 | method(sectionAlias) { 7 | const cy = this.cy; 8 | const cypress = this.cypress; 9 | 10 | cy.get('[data-element="section-' + sectionAlias + '"]', { 11 | log: false, 12 | }).click({ log: false }); 13 | 14 | cypress.log({ 15 | displayName: 'Umbraco Section ', 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoSetCurrentUserLanguage.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | import { JsonHelper } from '../../helpers/jsonHelper'; 3 | 4 | /** 5 | * This will set the currently logged in Users language 6 | * 7 | * @param language The iso code for the language you want 8 | * @returns The JSON data in the body of the response as an object 9 | */ 10 | export default class UmbracoSetCurrentUserLanguage extends CommandBase { 11 | _commandName = 'umbracoSetCurrentUserLanguage'; 12 | 13 | method(language) { 14 | const cy = this.cy; 15 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 16 | cy.request({ 17 | method: 'GET', 18 | url: 19 | this._relativeBackOfficePath + 20 | '/backoffice/umbracoapi/authentication/GetCurrentUser', 21 | followRedirect: true, 22 | headers: { 23 | Accept: 'application/json', 24 | 'X-UMB-XSRF-TOKEN': token.value, 25 | }, 26 | log: false, 27 | }).then((response) => { 28 | const searchBody = JsonHelper.getBody(response); 29 | return cy.umbracoApiRequest( 30 | this.relativeBackOfficePath + '/backoffice/umbracoapi/users/PostSaveUser', 31 | 'POST', 32 | { 33 | id: searchBody.id, 34 | parentId: -1, 35 | name: searchBody.name, 36 | username: searchBody.email, 37 | culture: language, 38 | email: searchBody.email, 39 | startContentIds: [], 40 | startMediaIds: [], 41 | userGroups: searchBody.userGroups 42 | }); 43 | }); 44 | }); 45 | } 46 | } -------------------------------------------------------------------------------- /src/cypress/commands/umbracoStylesheetExists.ts: -------------------------------------------------------------------------------- 1 | import UmbracoFileExists from './umbracoFileExists'; 2 | 3 | export default class UmbracoStyleSheetExists extends UmbracoFileExists { 4 | _commandName = 'umbracoStylesheetExists'; 5 | _endPoint = '/BackOffice/Api/StylesheetsTree/GetNodes?id=-1'; 6 | } 7 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoSuccessNotification.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoSuccessNotification extends CommandBase { 4 | _commandName = 'umbracoSuccessNotification'; 5 | 6 | method() { 7 | const cy = this.cy; 8 | const cypress = this.cypress; 9 | 10 | cy.get('.umb-notifications__notifications > .alert-success', { 11 | log: false, 12 | timeout: 60000, // This is often tested after a long running operation 13 | }); 14 | 15 | cypress.log({ 16 | displayName: 'Umbraco Notification Success ', 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoTreeItem.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoTreeItem extends CommandBase { 4 | _commandName = 'umbracoTreeItem'; 5 | 6 | method(treeName, itemNamePathArray) { 7 | const cy = this.cy; 8 | const cypress = this.cypress; 9 | 10 | cy.get('li > .umb-tree-root a[href*=' + treeName + ']', { 11 | log: false, 12 | }).then(($root) => { 13 | return this.findItem($root.closest('li'), itemNamePathArray, 0); 14 | }); 15 | 16 | cypress.log({ 17 | displayName: 'Umbraco Tree Item', 18 | message: treeName + ': ' + itemNamePathArray.join(' -> '), 19 | }); 20 | } 21 | 22 | findItem(parentElement, items, index) { 23 | const itemName = items[index]; 24 | 25 | const menuItems = parentElement.find('li'); 26 | 27 | let foundItem = null; 28 | for (const mi of menuItems) { 29 | const menuItem = cy.$$(mi); 30 | let breakLoop = false; 31 | // @ts-ignore 32 | const xx = menuItem.find('.umb-tree-item__label').text((index, text) => { 33 | if (text === itemName) { 34 | foundItem = menuItem; 35 | breakLoop = true; 36 | } 37 | }); 38 | if (breakLoop) { 39 | break; 40 | } 41 | } 42 | 43 | if (items.length === index + 1) { 44 | return foundItem; 45 | } else if (foundItem != null) { 46 | const li = foundItem.closest('li'); 47 | 48 | const ul = li.find('ul').first(); 49 | 50 | if (ul.hasClass('collapsed')) { 51 | li.find('[data-element="tree-item-expand"]').click(); 52 | } 53 | 54 | return cy 55 | .wrap(ul) 56 | .should('not.have.class', 'collapsed') 57 | .then((xx) => { 58 | return this.findItem(ul, items, index + 1); 59 | }); 60 | } else { 61 | return null; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoVerifyRenderedViewContent.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoVerifyRenderedViewContent extends CommandBase { 4 | _commandName = 'umbracoVerifyRenderedViewContent'; 5 | 6 | method(endpoint, expectedContent, removeWhitespace = false) { 7 | const cy = this.cy; 8 | 9 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | cy.request({ 11 | method: 'GET', 12 | url: endpoint, 13 | followRedirect: true, 14 | headers: { 15 | Accept: 'text/html', 16 | 'X-UMB-XSRF-TOKEN': token.value, 17 | }, 18 | log: false, 19 | }).then((response) => { 20 | let body = response.body; 21 | if (removeWhitespace) { 22 | expectedContent = expectedContent.replace(/\s/g, ''); 23 | body = body.replace(/\s/g, ''); 24 | } 25 | if (body === expectedContent) return true; 26 | return false; 27 | }); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoVerifyScriptContent.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoVerifyScriptContent extends CommandBase { 4 | _commandName = 'umbracoVerifyScriptContent'; 5 | 6 | method(fileName, expectedContent) { 7 | const cy = this.cy; 8 | 9 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | cy.request({ 11 | method: 'GET', 12 | url: '/scripts/' + fileName, 13 | followRedirect: true, 14 | headers: { 15 | Accept: 'application/javascript', 16 | 'X-UMB-XSRF-TOKEN': token.value, 17 | }, 18 | log: false, 19 | }).then((response) => { 20 | if (response.body === expectedContent) return true; 21 | return false; 22 | }); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/cypress/commands/umbracoVerifyStylesheetContent.ts: -------------------------------------------------------------------------------- 1 | import CommandBase from './commandBase'; 2 | 3 | export default class UmbracoVerifyStylesheetContent extends CommandBase { 4 | _commandName = 'umbracoVerifyStylesheetContent'; 5 | 6 | method(fileName, expectedContent) { 7 | const cy = this.cy; 8 | 9 | cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => { 10 | cy.request({ 11 | method: 'GET', 12 | url: '/css/' + fileName, 13 | followRedirect: true, 14 | headers: { 15 | Accept: 'text/css', 16 | 'X-UMB-XSRF-TOKEN': token.value, 17 | }, 18 | log: false, 19 | }).then((response) => { 20 | if (response.body === expectedContent) return true; 21 | return false; 22 | }); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/forms/builders/fields/conditions/formFieldConditionBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldConditionRuleBuilder } from './formFieldConditionRuleBuilder'; 2 | 3 | export class FormFieldConditionBuilder { 4 | parentBuilder; 5 | 6 | actionType; 7 | enabled; 8 | logicType; 9 | 10 | formFieldConditionRuleBuilders; 11 | 12 | constructor(parentBuilder) { 13 | this.parentBuilder = parentBuilder; 14 | this.formFieldConditionRuleBuilders = []; 15 | } 16 | 17 | withActionAndLogic(actionType, logicType) { 18 | this.actionType = actionType; 19 | this.logicType = logicType; 20 | this.enabled = true; 21 | } 22 | 23 | done() { 24 | return this.parentBuilder; 25 | } 26 | 27 | addRule() { 28 | const builder = new FormFieldConditionRuleBuilder(this); 29 | 30 | this.formFieldConditionRuleBuilders.push(builder); 31 | 32 | return builder; 33 | } 34 | 35 | build() { 36 | if (!this.enabled) { 37 | return {}; 38 | } 39 | 40 | return { 41 | enabled: this.enabled || false, 42 | actionType: this.actionType || '', 43 | logicType: this.logicType || null, 44 | rules: this.formFieldConditionRuleBuilders.map((builder) => { 45 | return builder.build(); 46 | }), 47 | }; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/forms/builders/fields/conditions/formFieldConditionRuleBuilder.ts: -------------------------------------------------------------------------------- 1 | export class FormFieldConditionRuleBuilder { 2 | parentBuilder; 3 | 4 | field; 5 | operator; 6 | value; 7 | 8 | constructor(parentBuilder) { 9 | this.parentBuilder = parentBuilder; 10 | } 11 | 12 | withContainsRule(fieldId, value) { 13 | this.field = fieldId; 14 | this.value = value; 15 | this.operator = 'Contains'; 16 | 17 | return this; 18 | } 19 | 20 | withIsRule(fieldId, value) { 21 | this.field = fieldId; 22 | this.value = value; 23 | this.operator = 'Is'; 24 | 25 | return this; 26 | } 27 | 28 | withIsNotRule(fieldId, value) { 29 | this.field = fieldId; 30 | this.value = value; 31 | this.operator = 'IsNot'; 32 | 33 | return this; 34 | } 35 | 36 | withGreaterThanRule(fieldId, value) { 37 | this.field = fieldId; 38 | this.value = value; 39 | this.operator = 'GreaterThen'; 40 | 41 | return this; 42 | } 43 | 44 | withLessThanRule(fieldId, value) { 45 | this.field = fieldId; 46 | this.value = value; 47 | this.operator = 'LessThen'; 48 | 49 | return this; 50 | } 51 | 52 | withStartsWithRule(fieldId, value) { 53 | this.field = fieldId; 54 | this.value = value; 55 | this.operator = 'StartsWith'; 56 | 57 | return this; 58 | } 59 | 60 | withEndsWithRule(fieldId, value) { 61 | this.field = fieldId; 62 | this.value = value; 63 | this.operator = 'EndsWith'; 64 | 65 | return this; 66 | } 67 | 68 | done() { 69 | return this.parentBuilder; 70 | } 71 | 72 | build() { 73 | return { 74 | field: this.field || null, 75 | operator: this.operator || null, 76 | value: this.value || null, 77 | }; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/forms/builders/fields/conditions/index.ts: -------------------------------------------------------------------------------- 1 | export { FormFieldConditionBuilder } from './formFieldConditionBuilder'; 2 | export { FormFieldConditionRuleBuilder } from './formFieldConditionRuleBuilder'; 3 | -------------------------------------------------------------------------------- /src/forms/builders/fields/dropDownFieldBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldBuilderBase } from './formFieldBuilderBase'; 2 | 3 | export class DropDownFieldBuilder extends FormFieldBuilderBase { 4 | fieldTypeId = '0dd29d42-a6a5-11de-a2f2-222256d89593'; 5 | removePrevalueEditor = true; 6 | prevalueSourceId = ''; 7 | parentBuilder; 8 | formFieldBuilderBase: FormFieldBuilderBase; 9 | 10 | withPrevalueSourceId(value: string) { 11 | this.prevalueSourceId = value; 12 | return this; 13 | } 14 | 15 | withPrevalues(values: string[]) { 16 | this.preValues = values; 17 | return this; 18 | } 19 | build() { 20 | const baseBuild = super.build(); 21 | // tslint:disable-next-line 22 | baseBuild['prevalueSourceId'] = this.prevalueSourceId; 23 | return baseBuild; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/forms/builders/fields/fileUploadFieldBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldBuilderBase } from './formFieldBuilderBase'; 2 | 3 | export class UploadFileFieldBuilder extends FormFieldBuilderBase { 4 | fieldTypeId = '84a17cf8-b711-46a6-9840-0e4a072ad000'; 5 | removePrevalueEditor = true; 6 | 7 | withDefaultValue(defaultValue: string) { 8 | // tslint:disable-next-line: no-string-literal 9 | this.settings['DefaultValue'] = defaultValue; 10 | return this; 11 | } 12 | 13 | withPlaceholder(placeholder) { 14 | // tslint:disable-next-line: no-string-literal 15 | this.settings['Placeholder'] = placeholder; 16 | return this; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/forms/builders/fields/formCheckboxFieldBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldBuilderBase } from './formFieldBuilderBase'; 2 | 3 | export class FormCheckboxFieldBuilder extends FormFieldBuilderBase { 4 | fieldTypeId = 'd5c0c390-ae9a-11de-a69e-666455d89593'; 5 | removePrevalueEditor = true; 6 | 7 | withDefaultValue(defaultValue: string) { 8 | // tslint:disable-next-line: no-string-literal 9 | this.settings['DefaultValue'] = defaultValue; 10 | 11 | return this; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/forms/builders/fields/formDateFieldBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldBuilderBase } from './formFieldBuilderBase'; 2 | 3 | export class FormDateFieldBuilder extends FormFieldBuilderBase { 4 | fieldTypeId = 'f8b4c3b8-af28-11de-9dd8-ef5956d89593'; 5 | removePrevalueEditor = true; 6 | } 7 | -------------------------------------------------------------------------------- /src/forms/builders/fields/formLongAnswerFieldBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldBuilderBase } from './formFieldBuilderBase'; 2 | 3 | export class FormLongAnswerFieldBuilder extends FormFieldBuilderBase { 4 | fieldTypeId = '023f09ac-1445-4bcb-b8fa-ab49f33bd046'; 5 | removePrevalueEditor = true; 6 | 7 | withDefaultValue(defaultValue: string) { 8 | // tslint:disable-next-line: no-string-literal 9 | this.settings['DefaultValue'] = defaultValue; 10 | return this; 11 | } 12 | 13 | withPlaceholder(placeholder) { 14 | // tslint:disable-next-line: no-string-literal 15 | this.settings['Placeholder'] = placeholder; 16 | return this; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/forms/builders/fields/formPasswordFieldBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldBuilderBase } from './formFieldBuilderBase'; 2 | 3 | export class FormPasswordFieldBuilder extends FormFieldBuilderBase { 4 | fieldTypeId = 'fb37bc60-d41e-11de-aeae-37c155d89593'; 5 | removePrevalueEditor = true; 6 | 7 | withPlaceholder(placeholder) { 8 | // tslint:disable-next-line: no-string-literal 9 | this.settings['Placeholder'] = placeholder; 10 | return this; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/forms/builders/fields/formShortAnswerFieldBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldBuilderBase } from './formFieldBuilderBase'; 2 | 3 | export class FormShortAnswerFieldBuilder extends FormFieldBuilderBase { 4 | fieldTypeId = '3f92e01b-29e2-4a30-bf33-9df5580ed52c'; 5 | removePrevalueEditor = true; 6 | 7 | withDefaultValue(defaultValue: string) { 8 | // tslint:disable-next-line: no-string-literal 9 | this.settings['DefaultValue'] = defaultValue; 10 | return this; 11 | } 12 | 13 | withPlaceholder(placeholder) { 14 | // tslint:disable-next-line: no-string-literal 15 | this.settings['Placeholder'] = placeholder; 16 | return this; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/forms/builders/fields/index.ts: -------------------------------------------------------------------------------- 1 | export { FormCheckboxFieldBuilder } from './formCheckboxFieldBuilder'; 2 | export { FormDateFieldBuilder } from './formDateFieldBuilder'; 3 | export { FormFieldBuilderBase } from './formFieldBuilderBase'; 4 | export { FormLongAnswerFieldBuilder } from './formLongAnswerFieldBuilder'; 5 | export { FormPasswordFieldBuilder } from './formPasswordFieldBuilder'; 6 | export { FormShortAnswerFieldBuilder } from './formShortAnswerFieldBuilder'; 7 | export { DropDownFieldBuilder } from './dropDownFieldBuilder'; 8 | export { UploadFileFieldBuilder } from './fileUploadFieldBuilder'; 9 | -------------------------------------------------------------------------------- /src/forms/builders/formFieldSetBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormContainerBuilder } from './formContainerBuilder'; 2 | 3 | export class FormFieldSetBuilder { 4 | parentBuilder; 5 | caption; 6 | 7 | formContainerBuilders; 8 | withCaption(caption) { 9 | this.caption = caption; 10 | return this; 11 | } 12 | 13 | constructor(parentBuilder) { 14 | this.parentBuilder = parentBuilder; 15 | this.formContainerBuilders = []; 16 | } 17 | 18 | addContainer() { 19 | const builder = new FormContainerBuilder(this); 20 | 21 | this.formContainerBuilders.push(builder); 22 | 23 | return builder; 24 | } 25 | 26 | done() { 27 | return this.parentBuilder; 28 | } 29 | 30 | build() { 31 | return { 32 | caption: this.caption || null, 33 | containers: this.formContainerBuilders.map((builder) => { 34 | return builder.build(); 35 | }), 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/forms/builders/formPageBuilder.ts: -------------------------------------------------------------------------------- 1 | import { FormFieldSetBuilder } from './formFieldSetBuilder'; 2 | 3 | export class FormPageBuilder { 4 | parentBuilder; 5 | caption; 6 | 7 | formFieldSetBuilders; 8 | 9 | withCaption(caption) { 10 | this.caption = caption; 11 | 12 | return this; 13 | } 14 | 15 | constructor(parentBuilder) { 16 | this.parentBuilder = parentBuilder; 17 | this.formFieldSetBuilders = []; 18 | } 19 | 20 | addFieldSet() { 21 | const builder = new FormFieldSetBuilder(this); 22 | 23 | this.formFieldSetBuilders.push(builder); 24 | 25 | return builder; 26 | } 27 | 28 | done() { 29 | return this.parentBuilder; 30 | } 31 | 32 | build() { 33 | return { 34 | caption: this.caption || null, 35 | fieldSets: this.formFieldSetBuilders.map((builder) => { 36 | return builder.build(); 37 | }), 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/forms/builders/helpers/contentBuilderHelper.ts: -------------------------------------------------------------------------------- 1 | import { ContentBuilder, Template, CmsDocumentType } from '../../..'; 2 | 3 | export class ContentBuilderHelper { 4 | public build(templateAlias, documentTypeAlias: string, properties?: any[]) { 5 | const content = new ContentBuilder() 6 | .withTemplateAlias(templateAlias) 7 | .withContentTypeAlias(documentTypeAlias) 8 | .addVariant() 9 | .withSave(true) 10 | .withPublish(true); 11 | properties?.forEach((property) => { 12 | content.addProperty().withAlias(property.alias).withValue(property.value).done(); 13 | }); 14 | 15 | return content.done().build(); 16 | } 17 | public buildContent_(templateBody, docTypeBody, formPickerAlias: string, formBody) { 18 | return new ContentBuilder() 19 | .withTemplateAlias(templateBody.alias) 20 | .withContentTypeAlias(docTypeBody.alias) 21 | .addVariant() 22 | .withSave(true) 23 | .withPublish(true) 24 | .addProperty() 25 | .withAlias(formPickerAlias) 26 | .withValue(formBody.id) 27 | .done() 28 | .done() 29 | .build(); 30 | } 31 | 32 | public insert(template: Template, documentType: CmsDocumentType, properties) { 33 | const content = this.build(template.alias, documentType.alias, properties); 34 | return cy.saveContent(content).then((contentBody) => contentBody); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/forms/builders/helpers/dataSourcesBuilderHelper.ts: -------------------------------------------------------------------------------- 1 | export class DataSourcesBuilderHelper { 2 | private readonly dataSourceWebServiceDataSourceId = '7edf567c-4230-4079-b3fb-cca44baf6b75'; 3 | private readonly dataSourceSqlDataSourceId = 'f19506f3-efea-4b13-a308-89348f69df91'; 4 | 5 | public insertWebService( 6 | name: string, 7 | settings: { 8 | InsertMethod: string; 9 | Password: string; 10 | ServiceName: string; 11 | ServiceUrl: string; 12 | UserName: string; 13 | }, 14 | ) { 15 | const payload = { 16 | formDataSourceTypeId: this.dataSourceWebServiceDataSourceId, 17 | name, 18 | settings, 19 | }; 20 | return cy.postRequest('/backoffice/UmbracoForms/DataSource/PostSave', payload).then((postsave) => postsave); 21 | } 22 | 23 | public insertSqlDatabase( 24 | name: string, 25 | settings: { 26 | Connection: string; 27 | Table: string; 28 | }, 29 | ) { 30 | const payload = { 31 | formDataSourceTypeId: this.dataSourceSqlDataSourceId, 32 | name, 33 | settings, 34 | }; 35 | return cy.postRequest('/backoffice/UmbracoForms/DataSource/PostSave', payload).then((postsave) => postsave); 36 | } 37 | public cleanUp() { 38 | return cy.deleteAllDataSources(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/forms/builders/helpers/documentTypeBuilderHelper.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | import { DocumentTypeBuilder, CmsDocumentType, Template, DataType } from '../../..'; 3 | import { PropertyBuilderHelper } from './propertyBuilderHelper'; 4 | 5 | export class DocumentTypeBuilderHelper { 6 | public build( 7 | documentType: CmsDocumentType, 8 | template: Template, 9 | items: { property: any; dataType: DataType }[], 10 | ): DocumentTypeBuilder { 11 | const builder = new DocumentTypeBuilder() 12 | .withName(documentType.name) 13 | .withAlias(documentType.alias) 14 | .withId(documentType.id) 15 | .withDefaultTemplate(template.alias) 16 | .withAllowAsRoot(true); 17 | 18 | return new PropertyBuilderHelper().build(builder.addGroup(), items); 19 | } 20 | 21 | public buildContentType_( 22 | templateBody, 23 | docTypePrefix: string, 24 | docTypeAlias: string, 25 | dataTypeBody, 26 | formPickerAlias: string, 27 | ): DocumentTypeBuilder { 28 | return new DocumentTypeBuilder() 29 | .withName(docTypePrefix + faker.random.uuid()) 30 | .withAlias(docTypeAlias) 31 | .withDefaultTemplate(decodeURI(templateBody)) 32 | .withAllowAsRoot(true) 33 | .addGroup() 34 | .addFormPickerProperty() 35 | .withDataTypeId(dataTypeBody.id) 36 | .withAlias(formPickerAlias) 37 | .done() 38 | .done() 39 | .build(); 40 | } 41 | public insert(documentTypeBuilder: DocumentTypeBuilder) { 42 | return cy.saveDocumentType(documentTypeBuilder.build()).then((documentTypeBody) => documentTypeBody); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/forms/builders/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export { ContentBuilderHelper } from './contentBuilderHelper'; 2 | export { DataSourcesBuilderHelper } from './dataSourcesBuilderHelper'; 3 | export { DataTypesBuilderHelper } from './dataTypesBuilderHelper'; 4 | export { DocumentTypeBuilderHelper } from './documentTypeBuilderHelper'; 5 | export { PrevalueSourcesBuilderHelper } from './prevalueSourcesBuilderHelper'; 6 | export { PropertyBuilderHelper } from './propertyBuilderHelper'; 7 | export { TemplateBuilderHelper } from './templateBuilderHelper'; 8 | export { FormBuilderHelper } from './formBuilderHelper'; 9 | -------------------------------------------------------------------------------- /src/forms/builders/helpers/prevalueSourcesBuilderHelper.ts: -------------------------------------------------------------------------------- 1 | export class PrevalueSourcesBuilderHelper { 2 | private readonly fieldPreValueSourceTextFileTypeId = '35c2053e-cbf7-4793-b27c-6e97b7671a2d'; 3 | private readonly fieldPreValueSourceDocumentTypeId = 'de996870-c45a-11de-8a39-0800200c9a66'; 4 | private readonly fieldPreValueSourceDataTypePrevalueId = 'ea773caf-fef2-491b-b5b7-6a3552b1a0e2'; 5 | 6 | public insertTextFile(name: string) { 7 | return cy.postFile('prevaluesource.txt', '/backoffice/UmbracoForms/PreValueFile/PostAddFile').then((settings) => { 8 | const payload = { 9 | fieldPreValueSourceTypeId: this.fieldPreValueSourceTextFileTypeId, 10 | name, 11 | settings: { TextFile: settings.FilePath }, 12 | }; 13 | return this.insert(payload); 14 | }); 15 | } 16 | 17 | public insertDocument(name: string, doctype: string) { 18 | const payload = { 19 | fieldPreValueSourceTypeId: this.fieldPreValueSourceDocumentTypeId, 20 | name, 21 | settings: { DocType: doctype }, 22 | }; 23 | return this.insert(payload); 24 | } 25 | public insertDataTypePrevalue(name: string, dataTypeId: number) { 26 | const payload = { 27 | fieldPreValueSourceTypeId: this.fieldPreValueSourceDataTypePrevalueId, 28 | name, 29 | settings: { DataTypeId: dataTypeId }, 30 | }; 31 | return this.insert(payload); 32 | } 33 | private insert(payload) { 34 | return cy.postRequest('/backoffice/UmbracoForms/PreValueSource/ValidateSettings', payload).then(() => { 35 | cy.postRequest('/backoffice/UmbracoForms/PreValueSource/PostSave', payload).then((postsave) => { 36 | cy.postRequest('/backoffice/UmbracoForms/PreValueSource/GetPreValues', payload).then(() => postsave); 37 | }); 38 | }); 39 | } 40 | 41 | public cleanUp() { 42 | return cy.deleteAllPreValues(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/forms/builders/helpers/propertyBuilderHelper.ts: -------------------------------------------------------------------------------- 1 | import { DataType, DocumentTypeBuilder, TextBoxProperty, DropDownProperty, FormPickerProperty } from '../../..'; 2 | import DocumentTypeGroupBuilder from '../../../cms/builders/documentTypes/documentTypeGroupBuilder'; 3 | 4 | export class PropertyBuilderHelper { 5 | public build( 6 | documentTypeGroupBuilder: DocumentTypeGroupBuilder, 7 | items: { property: any; dataType: DataType }[], 8 | ): DocumentTypeBuilder { 9 | items?.forEach((item: { property: any; dataType: DataType }) => { 10 | let builder; 11 | if (item.property instanceof TextBoxProperty) { 12 | builder = documentTypeGroupBuilder.addTextBoxProperty(); 13 | } else if (item.property instanceof DropDownProperty) { 14 | builder = documentTypeGroupBuilder.addDropDownProperty(); 15 | } else if (item.property instanceof FormPickerProperty) { 16 | builder = documentTypeGroupBuilder.addFormPickerProperty(); 17 | } 18 | builder.withDataTypeId(item.dataType.id).withAlias(item.property.alias).done(); 19 | }); 20 | return documentTypeGroupBuilder.done(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/forms/builders/iBuilder.ts: -------------------------------------------------------------------------------- 1 | export interface IBuilder { 2 | done(); 3 | build(); 4 | } 5 | -------------------------------------------------------------------------------- /src/forms/builders/index.ts: -------------------------------------------------------------------------------- 1 | export { FormBuilder } from './formBuilder'; 2 | export { FormContainerBuilder } from './formContainerBuilder'; 3 | export { FormFieldSetBuilder } from './formFieldSetBuilder'; 4 | export { FormPageBuilder } from './formPageBuilder'; 5 | -------------------------------------------------------------------------------- /src/forms/builders/workflows/index.ts: -------------------------------------------------------------------------------- 1 | export { FormWorkflowBuilder } from './formWorkflowBuilder'; 2 | export { WorkflowTypeSetting } from './workflowTypeSetting'; 3 | -------------------------------------------------------------------------------- /src/forms/builders/workflows/workflowTypeSetting.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | import { IBuilder } from '../iBuilder'; 3 | 4 | export class WorkflowTypeSetting { 5 | parentBuilder: IBuilder; 6 | 7 | description: string; 8 | name: string; 9 | prevalues: string[]; 10 | value: string; 11 | view: string; 12 | constructor(parentBuilder: IBuilder) { 13 | this.parentBuilder = parentBuilder; 14 | this.description = faker.lorem.words(4); 15 | this.name = ''; 16 | this.prevalues = ['']; 17 | this.value = ''; 18 | this.view = '/App_Plugins/UmbracoForms/Backoffice/Common/SettingTypes/TextField.html'; 19 | } 20 | 21 | withDescription(description: string): WorkflowTypeSetting { 22 | this.description = description; 23 | return this; 24 | } 25 | 26 | withName(name: string): WorkflowTypeSetting { 27 | this.name = name; 28 | return this; 29 | } 30 | 31 | withPrevalues(prevalues: string[]): WorkflowTypeSetting { 32 | this.prevalues = prevalues; 33 | return this; 34 | } 35 | 36 | withValue(value: string): WorkflowTypeSetting { 37 | this.value = value; 38 | return this; 39 | } 40 | withView(view: string): WorkflowTypeSetting { 41 | this.view = view; 42 | return this; 43 | } 44 | 45 | done(): IBuilder { 46 | return this.parentBuilder; 47 | } 48 | 49 | build() { 50 | return { 51 | alias: this.name, 52 | description: this.description, 53 | name: this.name, 54 | prevalues: this.prevalues, 55 | value: this.value, 56 | view: this.view, 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/forms/models/checkboxField.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from './formField'; 2 | 3 | export class CheckboxField extends FormField {} 4 | -------------------------------------------------------------------------------- /src/forms/models/dateField.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from './formField'; 2 | 3 | export class DateField extends FormField {} 4 | -------------------------------------------------------------------------------- /src/forms/models/dropDownField.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from './formField'; 2 | 3 | export class DropDownField extends FormField { 4 | constructor( 5 | id: string, 6 | public alias?: string, 7 | public caption?: string, 8 | public value?: string, 9 | containsSensitiveData?: boolean, 10 | mandatory?: boolean, 11 | requiredErrorMessage?: string, 12 | regex?: string, 13 | public prevalueSourceId?: string, 14 | public preValues?: string[], 15 | ) { 16 | super(id, containsSensitiveData, mandatory, requiredErrorMessage, regex); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/forms/models/fileUploadField.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from './formField'; 2 | 3 | export class FileUploadField extends FormField { 4 | constructor( 5 | id: string, 6 | public alias?: string, 7 | public caption?: string, 8 | containsSensitiveData?: boolean, 9 | mandatory?: boolean, 10 | requiredErrorMessage?: string, 11 | regex?: string, 12 | ) { 13 | super(id, containsSensitiveData, mandatory, requiredErrorMessage, regex); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/forms/models/formField.ts: -------------------------------------------------------------------------------- 1 | export class FormField { 2 | constructor( 3 | public id: string, 4 | public containsSensitiveData: boolean = false, 5 | public mandatory: boolean = false, 6 | public requiredErrorMessage: string = '', 7 | public regex: string = '', 8 | ) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/forms/models/formModel.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | export class FormModel { 3 | public name = faker.random.word(); 4 | } 5 | -------------------------------------------------------------------------------- /src/forms/models/index.ts: -------------------------------------------------------------------------------- 1 | export { CheckboxField } from './checkboxField'; 2 | export { DateField } from './dateField'; 3 | export { DropDownField } from './dropDownField'; 4 | export { FileUploadField } from './fileUploadField'; 5 | export { FormModel } from './formModel'; 6 | export { LongAnswerField } from './longAnswerField'; 7 | export { PasswordField } from './passwordField'; 8 | export { SendEmailRazorModel } from './sendEmailRazorModel'; 9 | export { ShortAnswerField } from './shortAnswerField'; 10 | export { Workflow } from './workflow'; 11 | export { WorkflowSettings } from './workflowSettings'; 12 | export { SaveAsUmbracoContentNodeWorkflowModel } from './saveAsUmbracoContentNodeWorkflowModel'; 13 | -------------------------------------------------------------------------------- /src/forms/models/longAnswerField.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from './formField'; 2 | 3 | export class LongAnswerField extends FormField { 4 | constructor( 5 | id: string, 6 | public alias?: string, 7 | public caption?: string, 8 | public value?: string, 9 | containsSensitiveData?: boolean, 10 | mandatory?: boolean, 11 | requiredErrorMessage?: string, 12 | regex?: string, 13 | ) { 14 | super(id, containsSensitiveData, mandatory, requiredErrorMessage, regex); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/forms/models/passwordField.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from './formField'; 2 | 3 | export class PasswordField extends FormField { 4 | constructor( 5 | id: string, 6 | public alias?: string, 7 | public caption?: string, 8 | public value?: string, 9 | containsSensitiveData?: boolean, 10 | mandatory?: boolean, 11 | requiredErrorMessage?: string, 12 | regex?: string, 13 | ) { 14 | super(id, containsSensitiveData, mandatory, requiredErrorMessage, regex); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/forms/models/saveAsUmbracoContentNodeWorkflowModel.ts: -------------------------------------------------------------------------------- 1 | export class SaveAsUmbracoContentNodeWorkflowModel { 2 | public workflowName: string; 3 | public rootNode: number; 4 | public includeSensitiveData = false; 5 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 6 | public executeOn = 0; 7 | public publish = 'True'; 8 | public documentType: { 9 | doctype?: string; 10 | nameField?: string; 11 | nameStaticValue?: number; 12 | properties?: [ 13 | { 14 | id: string; 15 | value: string; 16 | field: string; 17 | staticvalue: string; 18 | $$hashKey: string; 19 | }, 20 | ]; 21 | }; 22 | constructor(workflowName?: string) { 23 | this.workflowName = workflowName; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/forms/models/sendEmailRazorModel.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | 3 | export class SendEmailRazorModel { 4 | public workflowName: string; 5 | public includeSensitiveData = false; 6 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 7 | public executeOn = 0; 8 | public email: string = faker.internet.email(); 9 | public senderEmail: string = faker.internet.email(); 10 | public subject: string = faker.random.word(); 11 | public razorViewFilePath = 'Forms/Emails/Example-Template.cshtml'; 12 | public attachment = 'True'; 13 | 14 | constructor(workflowName: string) { 15 | this.workflowName = workflowName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/forms/models/shortAnswerField.ts: -------------------------------------------------------------------------------- 1 | import { FormField } from './formField'; 2 | 3 | export class ShortAnswerField extends FormField { 4 | constructor( 5 | id: string, 6 | public alias?: string, 7 | public caption?: string, 8 | public value?: string, 9 | containsSensitiveData?: boolean, 10 | mandatory?: boolean, 11 | requiredErrorMessage?: string, 12 | regex?: string, 13 | ) { 14 | super(id, containsSensitiveData, mandatory, requiredErrorMessage, regex); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/forms/models/workflow.ts: -------------------------------------------------------------------------------- 1 | import { WorkflowSettings } from './workflowSettings'; 2 | export class Workflow { 3 | executeOn = 0; 4 | workflowTypeId: string; 5 | includeSensitiveData = false; 6 | name: string; 7 | workflowTypeName: string; 8 | settings: any | WorkflowSettings[] = []; 9 | } 10 | -------------------------------------------------------------------------------- /src/forms/models/workflowSettings.ts: -------------------------------------------------------------------------------- 1 | export class WorkflowSettings { 2 | name: string; 3 | value: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/forms/workflows/changeRecordStateWorkflow.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | import faker from 'faker'; 3 | export enum RecordStateAction { 4 | 'Delete Record' = 0, 5 | 'Approve Record' = 1, 6 | } 7 | export class ChangeRecordStateWorkflow { 8 | public getWorkflow( 9 | workflowName: string = faker.random.word(), 10 | includeSensitiveData = false, 11 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 12 | executeOn = 0, 13 | action: RecordStateAction = RecordStateAction['Approve Record'], 14 | words: string[] = ['word'], 15 | ): Workflow { 16 | const workflow = new Workflow(); 17 | workflow.workflowTypeId = '4c40a092-0cb5-481d-96a7-a02d8e7cdb2f'; 18 | workflow.workflowTypeName = 'Change Record State'; 19 | workflow.name = workflowName; 20 | workflow.includeSensitiveData = includeSensitiveData; 21 | workflow.executeOn = executeOn; 22 | workflow.settings.push({ name: 'Words', value: words.join(',') }); 23 | workflow.settings.push({ name: 'Action', value: RecordStateAction[action] }); 24 | return workflow; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/forms/workflows/index.ts: -------------------------------------------------------------------------------- 1 | export { ChangeRecordStateWorkflow } from './changeRecordStateWorkflow'; 2 | export { PostAsXMLWorkflow } from './postAsXMLWorkflow'; 3 | export { SaveAsAnXMLFileWorkflow } from './saveAsAnXMLFileWorkflow'; 4 | export { SaveAsUmbracoContentNodeWorkflow } from './saveAsUmbracoContentNodeWorkflow'; 5 | export { SendEmailRazorWorkflow } from './sendEmailRazorWorkflow'; 6 | export { SendEmailWorkflow } from './sendEmailWorkflow'; 7 | export { SendFormToUrl } from './sendFormToUrl'; 8 | export { SendXsltTransformedEmail } from './sendXsltTransformedEmail'; 9 | -------------------------------------------------------------------------------- /src/forms/workflows/postAsXMLWorkflow.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | import faker from 'faker'; 3 | 4 | export enum Method { 5 | 'POST' = 0, 6 | 'GET' = 1, 7 | 'PUT' = 2, 8 | 'DELETE' = 3, 9 | } 10 | export class PostAsXMLWorkflow { 11 | public getWorkflow( 12 | workflowName: string = faker.random.word(), 13 | includeSensitiveData = false, 14 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 15 | executeOn = 0, 16 | url = '127.0.0.1', 17 | method: Method = Method.POST, 18 | xsltFile = '', 19 | user = 'user', 20 | password = 'password', 21 | headers?: [{ alias: string; value: string; staticValue: string; $$hashKey: string }], 22 | ): Workflow { 23 | const workflow = new Workflow(); 24 | workflow.workflowTypeId = '470eeb3a-cb15-4b08-9fc0-a2f091583332'; 25 | workflow.workflowTypeName = 'Post as XML'; 26 | workflow.name = workflowName; 27 | workflow.includeSensitiveData = includeSensitiveData; 28 | workflow.executeOn = executeOn; 29 | workflow.settings.push({ name: 'Url', value: url }); 30 | workflow.settings.push({ name: 'Method', value: Method[method] }); 31 | workflow.settings.push({ name: 'XsltFile', value: xsltFile }); 32 | workflow.settings.push({ name: 'Fields', value: headers }); 33 | workflow.settings.push({ name: 'Username', value: user }); 34 | workflow.settings.push({ name: 'Password', value: password }); 35 | return workflow; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/forms/workflows/saveAsAnXMLFileWorkflow.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | import faker from 'faker'; 3 | export class SaveAsAnXMLFileWorkflow { 4 | public getWorkflow( 5 | workflowName: string = faker.random.word(), 6 | includeSensitiveData = false, 7 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 8 | executeOn = 0, 9 | path = 'c:\\tmp', 10 | extension = '.mxl', 11 | xsltFile = '', 12 | ): Workflow { 13 | const workflow = new Workflow(); 14 | workflow.workflowTypeId = '9cc5854d-61a2-48f6-9f4a-8f3bdfafb521'; 15 | workflow.workflowTypeName = 'Save as an XML file'; 16 | workflow.name = workflowName; 17 | workflow.includeSensitiveData = includeSensitiveData; 18 | workflow.executeOn = executeOn; 19 | workflow.settings.push({ name: 'Path', value: path }); 20 | workflow.settings.push({ name: 'Extension', value: extension }); 21 | workflow.settings.push({ name: 'XsltFile', value: xsltFile }); 22 | return workflow; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/forms/workflows/saveAsUmbracoContentNodeWorkflow.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | 3 | import { SaveAsUmbracoContentNodeWorkflowModel } from '../models/saveAsUmbracoContentNodeWorkflowModel'; 4 | export class SaveAsUmbracoContentNodeWorkflow { 5 | public getWorkflow(model: SaveAsUmbracoContentNodeWorkflowModel): Workflow { 6 | const workflow = new Workflow(); 7 | workflow.workflowTypeId = '89fb1e31-9f36-4e08-9d1b-af1180d340db'; 8 | workflow.workflowTypeName = 'Save as Umbraco content node'; 9 | workflow.name = model.workflowName; 10 | workflow.includeSensitiveData = model.includeSensitiveData; 11 | workflow.executeOn = model.executeOn; 12 | workflow.settings.push({ name: 'Fields', value: model.documentType }); 13 | workflow.settings.push({ name: 'Publish', value: model.publish }); 14 | workflow.settings.push({ name: 'RootNode', value: model.rootNode }); 15 | return workflow; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/forms/workflows/sendEmailRazorWorkflow.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | import { SendEmailRazorModel } from '../models/sendEmailRazorModel'; 3 | export class SendEmailRazorWorkflow { 4 | public getWorkflow(model: SendEmailRazorModel): Workflow { 5 | const workflow = new Workflow(); 6 | workflow.workflowTypeId = '17c61629-d984-4e86-b43b-a8407b3efea9'; 7 | workflow.name = model.workflowName; 8 | workflow.includeSensitiveData = model.includeSensitiveData; 9 | workflow.workflowTypeName = 'Send email with template (Razor)'; 10 | workflow.executeOn = model.executeOn; 11 | workflow.settings.push({ name: 'Email', value: model.email }); 12 | workflow.settings.push({ name: 'SenderEmail', value: model.senderEmail }); 13 | workflow.settings.push({ name: 'Subject', value: model.subject }); 14 | workflow.settings.push({ name: 'RazorViewFilePath', value: model.razorViewFilePath }); 15 | workflow.settings.push({ name: 'Attachment', value: model.attachment }); 16 | return workflow; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/forms/workflows/sendEmailWorkflow.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | import faker from 'faker'; 3 | export class SendEmailWorkflow { 4 | public getWorkflow( 5 | workflowName: string = faker.random.word(), 6 | includeSensitiveData = false, 7 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 8 | executeOn = 0, 9 | email: string = faker.internet.email(), 10 | senderEmail: string = faker.internet.email(), 11 | subject: string = faker.random.word(), 12 | message: string = faker.lorem.lines(2), 13 | attachment = 'True', 14 | ): Workflow { 15 | const workflow = new Workflow(); 16 | workflow.workflowTypeId = 'e96badd7-05be-4978-b8d9-b3d733de70a5'; 17 | workflow.name = workflowName; 18 | workflow.workflowTypeName = 'Send email'; 19 | workflow.includeSensitiveData = includeSensitiveData; 20 | workflow.executeOn = executeOn; 21 | workflow.settings.push({ name: 'Email', value: email }); 22 | workflow.settings.push({ name: 'SenderEmail', value: senderEmail }); 23 | workflow.settings.push({ name: 'Subject', value: subject }); 24 | workflow.settings.push({ name: 'Message', value: message }); 25 | workflow.settings.push({ name: 'Attachment', value: attachment }); 26 | return workflow; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/forms/workflows/sendFormToUrl.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | import faker from 'faker'; 3 | 4 | export enum Method { 5 | 'POST' = 0, 6 | 'GET' = 1, 7 | 'PUT' = 2, 8 | 'DELETE' = 3, 9 | } 10 | export class SendFormToUrl { 11 | public getWorkflow( 12 | workflowName: string = faker.random.word(), 13 | includeSensitiveData = false, 14 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 15 | executeOn = 0, 16 | url = '127.0.0.1', 17 | method: Method = Method.POST, 18 | user = 'user', 19 | password = 'password', 20 | fields?: [{ alias: string; value: string; staticValue: string; $$hashKey: string }], 21 | ): Workflow { 22 | const workflow = new Workflow(); 23 | workflow.workflowTypeId = 'fd02c929-4e7d-4f90-b9fa-13d074a76688'; 24 | workflow.workflowTypeName = 'Send form to URL'; 25 | workflow.name = workflowName; 26 | workflow.includeSensitiveData = includeSensitiveData; 27 | workflow.executeOn = executeOn; 28 | workflow.settings.push({ name: 'Url', value: url }); 29 | workflow.settings.push({ name: 'Method', value: Method[method] }); 30 | workflow.settings.push({ name: 'Fields', value: fields }); 31 | workflow.settings.push({ name: 'UserName', value: user }); 32 | workflow.settings.push({ name: 'Password', value: password }); 33 | return workflow; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/forms/workflows/sendXsltTransformedEmail.ts: -------------------------------------------------------------------------------- 1 | import { Workflow } from '../models/workflow'; 2 | import faker from 'faker'; 3 | 4 | export class SendXsltTransformedEmail { 5 | public getWorkflow( 6 | workflowName: string = faker.random.word(), 7 | includeSensitiveData = false, 8 | // Need to figure out how to expose enum from package. 0=Submit, 1=Approve -> for workflows 9 | executeOn = 0, 10 | email: string = faker.internet.email(), 11 | senderEmail: string = faker.internet.email(), 12 | subject: string = faker.random.word(), 13 | xsltFile = '', 14 | ): Workflow { 15 | const workflow = new Workflow(); 16 | workflow.workflowTypeId = '616edfeb-badf-414b-89dc-d8655eb85998'; 17 | workflow.workflowTypeName = 'Send xslt transformed email'; 18 | workflow.name = workflowName; 19 | workflow.includeSensitiveData = includeSensitiveData; 20 | workflow.executeOn = executeOn; 21 | workflow.settings.push({ name: 'Email', value: email }); 22 | workflow.settings.push({ name: 'SenderEmail', value: senderEmail }); 23 | workflow.settings.push({ name: 'Subject', value: subject }); 24 | workflow.settings.push({ name: 'XsltFile', value: xsltFile }); 25 | 26 | return workflow; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/helpers/aliasHelper.ts: -------------------------------------------------------------------------------- 1 | import camelize from 'camelize'; 2 | 3 | export class AliasHelper { 4 | /** 5 | * Uses Camelize npm library to generate a safe alias from a string 6 | * that may contain spaces and dashes etc 7 | * 8 | * @param {string} text Input string 9 | * @returns {string} A camelcased string that starts with 'a' and ends with 'a' 10 | * @see {@link https://www.npmjs.com/package/camelize} 11 | */ 12 | static toSafeAlias(text: string): string { 13 | return 'a' + camelize(text) + 'a'; 14 | } 15 | 16 | /** 17 | * Camel cases a string by calling the toCamelCase() method 18 | * 19 | * @param {string} text Input string 20 | * @returns {string} A camelcased string 21 | */ 22 | static toAlias(text: string): string { 23 | return this.toCamelCase(text); 24 | } 25 | 26 | /** 27 | * Capatilze a string 28 | * 29 | * @param {string} text Input string 30 | * @returns {string} A capatilized string, of the first character only 31 | */ 32 | static capitalize(text: string): string { 33 | if (typeof text !== 'string') return ''; 34 | return text.charAt(0).toUpperCase() + text.slice(1); 35 | } 36 | 37 | /** 38 | * Convert a sentence into camelCase 39 | * `toCamelCase('My aWesome Example')` would return `myAwesomeExample` 40 | * 41 | * @param {string} sentenceCase Input string 42 | * @returns {string} A camel cased string 43 | */ 44 | static toCamelCase(sentenceCase: string): string { 45 | let out = ''; 46 | sentenceCase.split(' ').forEach((el, idx) => { 47 | const add = el.toLowerCase(); 48 | out += idx === 0 ? add : add[0].toUpperCase() + add.slice(1); 49 | }); 50 | return out; 51 | } 52 | 53 | /** 54 | * Removes dashes from UUID string 55 | * 56 | * @param {string} uuid A string representing a UUID 57 | * @returns {string} UUID without dashes 58 | */ 59 | static uuidToAlias(uuid: string): string { 60 | uuid = uuid.replace(/-/g, ''); 61 | return this.toAlias(uuid); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/helpers/jsonHelper.ts: -------------------------------------------------------------------------------- 1 | export class JsonHelper { 2 | /** 3 | * Expects the HTTP body response to be JSON 4 | * This will remove the `)]}',\n` if present 5 | * and return the correct JSON data as an object 6 | * 7 | * @param response The raw HTTP response from the server 8 | * @returns The JSON data in the body of the response as an object 9 | */ 10 | static getBody(response) { 11 | const junk = ")]}',\n"; 12 | let json = response.body; 13 | 14 | if (json.length === 0) { 15 | return null; 16 | } 17 | 18 | if (json.startsWith(junk)) { 19 | json = json.substr(junk.length); 20 | } 21 | return JSON.parse(json); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/helpers/responseHelper.ts: -------------------------------------------------------------------------------- 1 | export class ResponseHelper { 2 | /** 3 | * This strips the first 6 characters of the response body 4 | * as it assumes it will **always** contain the junk json data `)]}',\n` 5 | * 6 | * It would be better to use jsonHelper.getBody() 7 | * as it checks for its presence of the data 8 | * 9 | * @param response The raw HTTP response from the server 10 | * @returns The JSON data in the body of the response as an object 11 | * @deprecated Please use jsonHelper.getBody instead 12 | * @see jsonHelper.getBody() 13 | */ 14 | static getResponseBody(response) { 15 | return JSON.parse(response.body.substr(6)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/builders/dataTypeBuilder.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import faker from 'faker' 3 | import { FormPickerDataTypeBuilder } from '../../src'; 4 | 5 | 6 | describe('DataType Builders', () => { 7 | it('FormPickerDataTypeBuilder Default', () => { 8 | const actual = new FormPickerDataTypeBuilder() 9 | .build(); 10 | 11 | assert.equal(actual.selectedEditor ,"UmbracoForms.FormPicker"); 12 | assert.equal(actual.selectedEditor ,"UmbracoForms.FormPicker"); 13 | }); 14 | 15 | it('FormPickerDataTypeBuilder Custom single form', () => { 16 | 17 | const name = faker.lorem.sentence(); 18 | const id = faker.random.number(); 19 | const formId = faker.random.uuid(); 20 | 21 | const actual = new FormPickerDataTypeBuilder() 22 | .withSaveAction() 23 | .withId(id) 24 | .withName(name) 25 | .withAllowedForm(formId) 26 | .build(); 27 | 28 | assert.equal(actual.id, id); 29 | assert.equal(actual.name, name); 30 | assert.equal(actual.action, "save"); 31 | assert.lengthOf(actual.getPrevalues(), 1); 32 | assert.equal(actual.getPrevalues()[0].key, "allowedForms"); 33 | assert.lengthOf(actual.getPrevalues()[0].value,1); 34 | assert.equal(actual.getPrevalues()[0].value[0], formId); 35 | }); 36 | 37 | 38 | it('FormPickerDataTypeBuilder Custom multi form', () => { 39 | const formId1 = faker.random.uuid(); 40 | const formId2 = faker.random.uuid(); 41 | 42 | const actual = new FormPickerDataTypeBuilder() 43 | .withSaveNewAction() 44 | .withAllowedForms([formId1, formId2]) 45 | .build(); 46 | 47 | assert.equal(actual.action, "saveNew"); 48 | assert.lengthOf(actual.getPrevalues(), 1); 49 | assert.equal(actual.getPrevalues()[0].key, "allowedForms"); 50 | assert.lengthOf(actual.getPrevalues()[0].value,2); 51 | assert.equal(actual.getPrevalues()[0].value[0], formId1); 52 | assert.equal(actual.getPrevalues()[0].value[1], formId2); 53 | }); 54 | 55 | 56 | }); 57 | -------------------------------------------------------------------------------- /tests/builders/documentTypeBuilder.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import faker from 'faker' 3 | import { DocumentTypeBuilder } from '../../src'; 4 | 5 | describe('DocumentTypeBuilder', () => { 6 | it('Default build', () => { 7 | const actual = new DocumentTypeBuilder() 8 | .build(); 9 | assert(actual.alias != null, 'The alias must be set'); 10 | }); 11 | 12 | it('Custom build', () => { 13 | const dataTypeId = faker.random.uuid(); 14 | const formPickerAlias = faker.hacker.adjective(); 15 | const pickerLabel = faker.lorem.sentence(); 16 | 17 | const actual = new DocumentTypeBuilder() 18 | .withAllowAsRoot(true) 19 | .addGroup() 20 | .addFormPickerProperty() 21 | .withDataTypeId(dataTypeId) 22 | .withAlias(formPickerAlias) 23 | .done() 24 | .addFormPickerProperty() 25 | .withLabel(pickerLabel) 26 | .done() 27 | .done() 28 | .build(); 29 | 30 | assert(actual.alias != null, 'The alias must be set'); 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /tests/cypress/commands/commandBase.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import faker from "faker"; 3 | import td from 'testdouble' 4 | import cypressTestDouble, {addMock} from "../testDoubles/cypressTestDouble"; 5 | import cyTestDouble from "../testDoubles/cyTestDouble"; 6 | import CommandBase from '../../../src/cypress/commands/commandBase'; 7 | 8 | 9 | 10 | describe('CommandBase', () => { 11 | const sut = new CommandBase( "/umbraco", cyTestDouble, cypressTestDouble); 12 | 13 | it('register command must call the method', () => { 14 | const commandName = faker.name.findName(); 15 | let captor = td.matchers.captor(); 16 | 17 | // ensure we call the method of the class self, and therefore expect the same error 18 | td.when(addMock(commandName, captor.capture())).thenDo(() => captor.value()); 19 | 20 | sut.commandName = commandName; 21 | 22 | assert.throws(() => sut.registerCommand(), Error, /You have to implement the method()/); 23 | 24 | }); 25 | 26 | it('method must throw error on base class (alternative to abstract)', () => { 27 | assert.throws(() => sut.method(0,0,0,0,0,0,0), Error, /You have to implement the method()/); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /tests/cypress/commands/umbracoLogin.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | 3 | describe('UmbracoLogin', () => { 4 | it('Not implemented', () =>{ 5 | assert(true); 6 | }); 7 | }); 8 | // import { assert } from 'chai'; 9 | // import UmbracoLogin from "../../../src/cypress/commands/umbracoLogin"; 10 | // import faker from "faker"; 11 | // import td from 'testdouble' 12 | // import cypressTestDouble from "../testDoubles/cypressTestDouble"; 13 | // import cyTestDouble, {clearCookiesMock, clearLocalStorageMock, hasClassMock} from "../testDoubles/cyTestDouble"; 14 | // 15 | // describe('UmbracoLogin', () => { 16 | // const sut = new UmbracoLogin( "/umbraco", cyTestDouble, cypressTestDouble); 17 | // 18 | // it('Happy path - Success, visit backoffice with tour', () => { 19 | // //Arrage 20 | // let captor = td.matchers.captor(); 21 | // let username = faker.name.findName(); 22 | // let password = faker.name.findName(); 23 | // 24 | // //Mock 25 | // td.when(cypressTestDouble.Commands.add("umbracoLogin", captor.capture())).thenDo(() => captor.value(username, password)); 26 | // td.when(hasClassMock('umb-tour-is-visible')).thenReturn(false); 27 | // 28 | // //Act 29 | // sut.method(username, password); 30 | // 31 | // //Assert 32 | // 33 | // //Verify 34 | // td.verify(clearCookiesMock()); 35 | // td.verify(clearLocalStorageMock()); 36 | // td.verify(hasClassMock('umb-tour-is-visible')); 37 | // }); 38 | // }); 39 | -------------------------------------------------------------------------------- /tests/cypress/testDoubles/cyTestDouble.ts: -------------------------------------------------------------------------------- 1 | import td from 'testdouble' 2 | 3 | export const clearCookiesMock = td.func('cy.clearCookies'); 4 | export const clearLocalStorageMock = td.func('cy.clearLocalStorageMock'); 5 | export const logMock = td.func('cy.log'); 6 | export const hasClassMock = td.func('cy.get(...).should(...).hasClass'); 7 | export const typeMock = td.func('cy.get(...).type'); 8 | 9 | export default { 10 | clearCookies: () => clearCookiesMock(), 11 | clearLocalStorage: () => clearLocalStorageMock(), 12 | log: () => logMock(), 13 | 14 | visit: (fn1) => { 15 | return { 16 | then: (fn) => fn(), 17 | } 18 | }, 19 | 20 | get: (fn1) => { 21 | return { 22 | should: (s) => s({ 23 | hasClass: (a) => hasClassMock(a), 24 | }), 25 | click: (fn1) => { 26 | return { 27 | then: (fn) => fn(), 28 | } 29 | }, 30 | type: (text) => typeMock(text) 31 | 32 | } 33 | }, 34 | 35 | request: (fn1) => { 36 | let responseBody = ')]}\',\n{"test":"json"}'; 37 | return { 38 | 39 | 40 | then: (fn) => fn({body:responseBody}), 41 | } 42 | }, 43 | 44 | getCookie: (fn1) => { 45 | return { 46 | 47 | then: (fn) => fn({token:"test"}), 48 | } 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /tests/cypress/testDoubles/cypressTestDouble.ts: -------------------------------------------------------------------------------- 1 | import td from 'testdouble' 2 | 3 | export const addMock = td.func('Cypress.Commands.add'); 4 | export default { 5 | Commands: { 6 | add: (name, func) => addMock(name, func) 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "types": [ 4 | "jest" 5 | ], 6 | "include": [ 7 | "**/*.ts" 8 | ] 9 | 10 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./lib", 6 | "sourceMap": false, 7 | "declaration": true, 8 | "declarationDir": "./lib/types", 9 | "module": "CommonJS", 10 | "moduleResolution": "node", 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "esModuleInterop": true, 14 | "importHelpers": true, 15 | "target": "es6", 16 | "inlineSourceMap": true, 17 | "types": [ 18 | "cypress", 19 | "node" 20 | ], 21 | "lib": [ 22 | "es5", 23 | "dom" 24 | ], 25 | "plugins": [ 26 | { 27 | "name": "typescript-tslint-plugin", 28 | "alwaysShowRuleFailuresAsWarnings": false, 29 | "ignoreDefinitionFiles": true, 30 | "configFile": "tslint.json", 31 | "suppressWhileTypeErrorsPresent": false 32 | } 33 | ] 34 | }, 35 | "include": [ 36 | "src/**/*.ts" 37 | ], 38 | } 39 | --------------------------------------------------------------------------------