Просмотр исходного кода

Merge pull request #671 from smiclea/unit-tests

Implement unit testing framework and add unit tests
Nashwan Azhari 4 лет назад
Родитель
Сommit
c624aa58a3
100 измененных файлов с 1013 добавлено и 525 удалено
  1. 0 1
      .eslintignore
  2. 2 0
      .eslintrc
  3. 1 1
      .storybook/preview.js
  4. 2 3
      babel.config.js
  5. 202 0
      jest.config.ts
  6. 13 4
      package.json
  7. 0 16
      private/jest/componentsMock.js
  8. 0 1
      private/jest/fileMock.js
  9. 0 4
      private/jest/setupTests.js
  10. 0 3
      private/jest/shim.js
  11. 13 2
      src/components/App.tsx
  12. 99 0
      src/components/modules/DashboardModule/DashboardActivity/DashboardActivity.spec.tsx
  13. 4 4
      src/components/modules/DashboardModule/DashboardActivity/DashboardActivity.tsx
  14. 85 0
      src/components/modules/DashboardModule/DashboardBarChart/DashboardBarChart.spec.tsx
  15. 2 4
      src/components/modules/DashboardModule/DashboardBarChart/DashboardBarChart.tsx
  16. 1 1
      src/components/modules/DashboardModule/DashboardExecutions/DashboardExecutions.tsx
  17. 1 2
      src/components/modules/DetailsModule/DetailsContentHeader/DetailsContentHeader.tsx
  18. 1 2
      src/components/modules/EndpointModule/ChooseProvider/ChooseProvider.tsx
  19. 11 11
      src/components/modules/EndpointModule/EndpointDetailsContent/EndpointDetailsContent.tsx
  20. 1 4
      src/components/modules/EndpointModule/EndpointDuplicateOptions/EndpointDuplicateOptions.tsx
  21. 4 5
      src/components/modules/EndpointModule/EndpointListItem/EndpointListItem.tsx
  22. 1 4
      src/components/modules/EndpointModule/EndpointLogos/EndpointLogos.tsx
  23. 1 1
      src/components/modules/EndpointModule/EndpointModal/EndpointModal.tsx
  24. 7 7
      src/components/modules/EndpointModule/EndpointValidation/EndpointValidation.tsx
  25. 0 3
      src/components/modules/LoginModule/LoginForm/LoginForm.tsx
  26. 1 2
      src/components/modules/LoginModule/LoginFormField/LoginFormField.tsx
  27. 1 2
      src/components/modules/LoginModule/LoginOptions/LoginOptions.tsx
  28. 1 1
      src/components/modules/NavigationModule/DetailsNavigation/test.tsx
  29. 0 2
      src/components/modules/NavigationModule/Navigation/Navigation.tsx
  30. 0 1
      src/components/modules/NavigationModule/NavigationMini/NavigationMini.tsx
  31. 3 9
      src/components/modules/ProjectModule/ProjectDetailsContent/ProjectDetailsContent.tsx
  32. 0 2
      src/components/modules/ProjectModule/ProjectDetailsContent/test.tsx
  33. 5 7
      src/components/modules/ProjectModule/ProjectListItem/ProjectListItem.tsx
  34. 0 6
      src/components/modules/ProjectModule/ProjectMemberModal/ProjectMemberModal.tsx
  35. 0 3
      src/components/modules/ProjectModule/ProjectModal/ProjectModal.tsx
  36. 3 4
      src/components/modules/TransferModule/Executions/Executions.tsx
  37. 7 9
      src/components/modules/TransferModule/MainDetails/MainDetails.tsx
  38. 0 1
      src/components/modules/TransferModule/MigrationDetailsContent/MigrationDetailsContent.tsx
  39. 0 3
      src/components/modules/TransferModule/ReplicaDetailsContent/ReplicaDetailsContent.tsx
  40. 2 3
      src/components/modules/TransferModule/ReplicaExecutionOptions/ReplicaExecutionOptions.tsx
  41. 2 2
      src/components/modules/TransferModule/ReplicaMigrationOptions/ReplicaMigrationOptions.tsx
  42. 1 2
      src/components/modules/TransferModule/Schedule/Schedule.tsx
  43. 1 10
      src/components/modules/TransferModule/ScheduleItem/ScheduleItem.tsx
  44. 1 1
      src/components/modules/TransferModule/TaskItem/TaskItem.tsx
  45. 0 1
      src/components/modules/TransferModule/Tasks/Tasks.tsx
  46. 1 4
      src/components/modules/TransferModule/Timeline/Timeline.tsx
  47. 2 2
      src/components/modules/TransferModule/TransferDetailsTable/TransferDetailsTable.tsx
  48. 1 2
      src/components/modules/TransferModule/TransferItemModal/TransferItemModal.tsx
  49. 4 4
      src/components/modules/TransferModule/TransferListItem/TransferListItem.tsx
  50. 0 0
      src/components/modules/TransferModule/TransferListItem/images/arrow.svg
  51. 0 0
      src/components/modules/TransferModule/TransferListItem/images/schedule.svg
  52. 6 0
      src/components/modules/TransferModule/TransferListItem/package.json
  53. 3 3
      src/components/modules/TransferModule/TransferListItem/story.tsx
  54. 0 0
      src/components/modules/TransferModule/TransferListItem/test.tsx
  55. 6 9
      src/components/modules/UserModule/UserDetailsContent/UserDetailsContent.tsx
  56. 6 7
      src/components/modules/UserModule/UserListItem/UserListItem.tsx
  57. 0 3
      src/components/modules/UserModule/UserModal/UserModal.tsx
  58. 1 1
      src/components/modules/WizardModule/WizardBreadcrumbs/WizardBreadcrumbs.tsx
  59. 0 3
      src/components/modules/WizardModule/WizardEndpointList/WizardEndpointList.tsx
  60. 4 7
      src/components/modules/WizardModule/WizardInstances/WizardInstances.tsx
  61. 2 2
      src/components/modules/WizardModule/WizardNetworks/WizardNetworks.tsx
  62. 0 1
      src/components/modules/WizardModule/WizardOptions/WizardOptions.tsx
  63. 0 1
      src/components/modules/WizardModule/WizardStorage/WizardStorage.tsx
  64. 7 10
      src/components/modules/WizardModule/WizardSummary/WizardSummary.tsx
  65. 0 1
      src/components/modules/WizardModule/WizardType/WizardType.tsx
  66. 1 1
      src/components/smart/AssessmentsPage/AssessmentsPage.tsx
  67. 1 1
      src/components/smart/DashboardPage/DashboardPage.tsx
  68. 1 1
      src/components/smart/EndpointsPage/EndpointsPage.tsx
  69. 1 1
      src/components/smart/LogsPage/LogsPage.tsx
  70. 3 3
      src/components/smart/MigrationsPage/MigrationsPage.tsx
  71. 1 1
      src/components/smart/MinionPoolsPage/MinionPoolsPage.tsx
  72. 0 0
      src/components/smart/PageHeader/PageHeader.tsx
  73. 0 0
      src/components/smart/PageHeader/package.json
  74. 0 0
      src/components/smart/PageHeader/story.tsx
  75. 1 1
      src/components/smart/ProjectsPage/ProjectsPage.tsx
  76. 3 3
      src/components/smart/ReplicasPage/ReplicasPage.tsx
  77. 1 1
      src/components/smart/UsersPage/UsersPage.tsx
  78. 71 0
      src/components/ui/AlertModal/AlertModal.spec.tsx
  79. 7 7
      src/components/ui/AlertModal/AlertModal.tsx
  80. 0 56
      src/components/ui/AlertModal/test.tsx
  81. 46 0
      src/components/ui/Arrow/Arrow.spec.tsx
  82. 36 0
      src/components/ui/AutocompleteInput/AutocompleteInput.spec.tsx
  83. 0 2
      src/components/ui/AutocompleteInput/AutocompleteInput.tsx
  84. 37 0
      src/components/ui/Button/Button.spec.tsx
  85. 0 43
      src/components/ui/Button/test.tsx
  86. 39 0
      src/components/ui/Checkbox/Checkbox.spec.tsx
  87. 0 2
      src/components/ui/Checkbox/Checkbox.tsx
  88. 0 44
      src/components/ui/Checkbox/test.tsx
  89. 14 15
      src/components/ui/CopyButton/CopyButton.spec.tsx
  90. 38 0
      src/components/ui/CopyMultilineValue/CopyMultilineValue.spec.tsx
  91. 0 2
      src/components/ui/CopyMultilineValue/CopyMultilineValue.tsx
  92. 0 38
      src/components/ui/CopyMultilineValue/test.tsx
  93. 34 0
      src/components/ui/CopyValue/CopyValue.spec.tsx
  94. 0 3
      src/components/ui/CopyValue/CopyValue.tsx
  95. 0 39
      src/components/ui/CopyValue/test.tsx
  96. 61 0
      src/components/ui/DatetimePicker/DatetimePicker.spec.tsx
  97. 0 1
      src/components/ui/DatetimePicker/DatetimePicker.tsx
  98. 0 42
      src/components/ui/DatetimePicker/test.tsx
  99. 94 0
      src/components/ui/Dropdowns/ActionDropdown/ActionDropdown.spec.tsx
  100. 1 4
      src/components/ui/Dropdowns/ActionDropdown/ActionDropdown.tsx

+ 0 - 1
.eslintignore

@@ -1 +0,0 @@
-*.js

+ 2 - 0
.eslintrc

@@ -32,6 +32,8 @@
     "*.log",
     "*.log",
     "*.jpg",
     "*.jpg",
     "*.woff",
     "*.woff",
+    "*.js",
+    "*.snap",
     "src/**/test.tsx",
     "src/**/test.tsx",
     "src/**/package.json"
     "src/**/package.json"
   ],
   ],

+ 1 - 1
.storybook/preview.js

@@ -3,7 +3,7 @@ import { addDecorator } from '@storybook/react'
 import styled, { createGlobalStyle } from 'styled-components'
 import styled, { createGlobalStyle } from 'styled-components'
 
 
 import { ThemePalette, ThemeProps } from '@src/components/Theme'
 import { ThemePalette, ThemeProps } from '@src/components/Theme'
-import Fonts from '../src/components/atoms/Fonts'
+import Fonts from '@src/components/ui/Fonts'
 import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
 import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
 
 
 const Wrapper = styled.div`
 const Wrapper = styled.div`

+ 2 - 3
babel.config.js

@@ -3,7 +3,7 @@ module.exports = api => {
 
 
   const common = {
   const common = {
     presets: [
     presets: [
-      ['@babel/env', { targets: { node: true } }],
+      ['@babel/env', { targets: { node: 'current' } }],
       '@babel/typescript',
       '@babel/typescript',
       '@babel/react',
       '@babel/react',
     ],
     ],
@@ -20,8 +20,7 @@ module.exports = api => {
       '@babel/plugin-proposal-optional-chaining',
       '@babel/plugin-proposal-optional-chaining',
     ],
     ],
   }
   }
-
-  if (process.env.NODE_MODE === 'development') {
+  if (process.env.NODE_MODE === 'development' || process.env.NODE_ENV === 'test') {
     common.plugins.push(['babel-plugin-styled-components', { displayName: true, minify: false }])
     common.plugins.push(['babel-plugin-styled-components', { displayName: true, minify: false }])
   } else {
   } else {
     common.plugins.push(['babel-plugin-styled-components', { displayName: false, minify: true }])
     common.plugins.push(['babel-plugin-styled-components', { displayName: false, minify: true }])

+ 202 - 0
jest.config.ts

@@ -0,0 +1,202 @@
+/*
+ * For a detailed explanation regarding each configuration property and type check, visit:
+ * https://jestjs.io/docs/configuration
+ */
+
+export default {
+  // All imported modules in your tests should be mocked automatically
+  // automock: false,
+
+  // Stop running tests after `n` failures
+  // bail: 0,
+
+  // The directory where Jest should store its cached dependency information
+  // cacheDirectory: "/private/var/folders/gx/mbf75kfj2l3c7lpwklx2ltnw0000gn/T/jest_dx",
+
+  // Automatically clear mock calls and instances between every test
+  clearMocks: true,
+
+  // Indicates whether the coverage information should be collected while executing the test
+  // collectCoverage: false,
+
+  // An array of glob patterns indicating a set of files for which coverage information should be collected
+  // collectCoverageFrom: undefined,
+
+  // The directory where Jest should output its coverage files
+  // coverageDirectory: undefined,
+
+  // An array of regexp pattern strings used to skip coverage collection
+  // coveragePathIgnorePatterns: [
+  //   "/node_modules/"
+  // ],
+
+  // Indicates which provider should be used to instrument code for coverage
+  coverageProvider: 'v8',
+
+  // A list of reporter names that Jest uses when writing coverage reports
+  // coverageReporters: [
+  //   "json",
+  //   "text",
+  //   "lcov",
+  //   "clover"
+  // ],
+
+  // An object that configures minimum threshold enforcement for coverage results
+  // coverageThreshold: undefined,
+
+  // A path to a custom dependency extractor
+  // dependencyExtractor: undefined,
+
+  // Make calling deprecated APIs throw helpful error messages
+  // errorOnDeprecated: false,
+
+  // Force coverage collection from ignored files using an array of glob patterns
+  // forceCoverageMatch: [],
+
+  // A path to a module which exports an async function that is triggered once before all test suites
+  // globalSetup: undefined,
+
+  // A path to a module which exports an async function that is triggered once after all test suites
+  // globalTeardown: undefined,
+
+  // A set of global variables that need to be available in all test environments
+  // globals: {},
+
+  // The maximum amount of workers used to run your tests. Can be specified as % or a number.
+  // E.g.maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number.maxWorkers: 2 will use a maximum of 2 workers.
+  // maxWorkers: "50%",
+
+  // An array of directory names to be searched recursively up from the requiring module's location
+  // moduleDirectories: [
+  //   "node_modules"
+  // ],
+
+  // An array of file extensions your modules use
+  // moduleFileExtensions: [
+  //   "js",
+  //   "jsx",
+  //   "ts",
+  //   "tsx",
+  //   "json",
+  //   "node"
+  // ],
+
+  // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
+  moduleNameMapper: {
+    '@src/(.*)': '<rootDir>/src/$1',
+    '@tests/(.*)': '<rootDir>/tests/$1',
+  },
+
+  // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
+  // modulePathIgnorePatterns: [],
+
+  // Activates notifications for test results
+  // notify: false,
+
+  // An enum that specifies notification mode. Requires { notify: true }
+  // notifyMode: "failure-change",
+
+  // A preset that is used as a base for Jest's configuration
+  // preset: undefined,
+
+  // Run tests from one or more projects
+  // projects: undefined,
+
+  // Use this configuration option to add custom reporters to Jest
+  // reporters: undefined,
+
+  // Automatically reset mock state between every test
+  // resetMocks: false,
+
+  // Reset the module registry before running each individual test
+  // resetModules: false,
+
+  // A path to a custom resolver
+  // resolver: undefined,
+
+  // Automatically restore mock state between every test
+  // restoreMocks: false,
+
+  // The root directory that Jest should scan for tests and modules within
+  // rootDir: undefined,
+
+  // A list of paths to directories that Jest should use to search for files in
+  // roots: [
+  //   "<rootDir>"
+  // ],
+
+  // Allows you to use a custom runner instead of Jest's default test runner
+  // runner: "jest-runner",
+
+  // The paths to modules that run some code to configure or set up the testing environment before each test
+  setupFiles: [
+    '<rootDir>/tests/setup.js',
+  ],
+
+  // A list of paths to modules that run some code to configure or set up the testing framework before each test
+  // setupFilesAfterEnv: [],
+
+  // The number of seconds after which a test is considered as slow and reported as such in the results.
+  // slowTestThreshold: 5,
+
+  // A list of paths to snapshot serializer modules Jest should use for snapshot testing
+  // snapshotSerializers: [],
+
+  // The test environment that will be used for testing
+  testEnvironment: 'jsdom',
+
+  // Options that will be passed to the testEnvironment
+  // testEnvironmentOptions: {},
+
+  // Adds a location field to test results
+  // testLocationInResults: false,
+
+  // The glob patterns Jest uses to detect test files
+  testMatch: [
+    '**/*.spec.tsx',
+  ],
+
+  // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
+  // testPathIgnorePatterns: [
+  //   "/node_modules/"
+  // ],
+
+  // The regexp pattern or array of patterns that Jest uses to detect test files
+  // testRegex: [],
+
+  // This option allows the use of a custom results processor
+  // testResultsProcessor: undefined,
+
+  // This option allows use of a custom test runner
+  // testRunner: "jest-circus/runner",
+
+  // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
+  // testURL: "http://localhost",
+
+  // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
+  // timers: "real",
+
+  // A map from regular expressions to paths to transformers
+  transform: {
+    '\\.[jt]sx?$': 'babel-jest',
+    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/tests/fileTransform.js',
+  },
+
+  // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
+  // transformIgnorePatterns: [
+  //   "/node_modules/",
+  //   "\\.pnp\\.[^\\/]+$"
+  // ],
+
+  // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
+  // unmockedModulePathPatterns: undefined,
+
+  // Indicates whether each individual test should be reported during the run
+  // verbose: undefined,
+
+  // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
+  // watchPathIgnorePatterns: [],
+
+  // Whether to use watchman for file crawling
+  // watchman: true,
+}

+ 13 - 4
package.json

@@ -13,25 +13,32 @@
     "server-debug": "node --inspect server",
     "server-debug": "node --inspect server",
     "tsc": "npx tsc --skipLibCheck",
     "tsc": "npx tsc --skipLibCheck",
     "eslint": "npx eslint \"src/**\" \"server/**\"",
     "eslint": "npx eslint \"src/**\" \"server/**\"",
-    "test-release": "node ./server/testRelease",
+    "test": "jest",
+    "test-release": "node ./tests/testRelease",
+    "test-coverage": "node ./tests/testCoverage",
     "storybook": "start-storybook"
     "storybook": "start-storybook"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@storybook/react": "^6.4.13",
     "@storybook/react": "^6.4.13",
+    "@testing-library/dom": "^8.11.1",
+    "@testing-library/react": "^12.1.2",
+    "@testing-library/user-event": "^13.5.0",
     "@types/connect": "^3.4.33",
     "@types/connect": "^3.4.33",
     "@types/express": "^4.17.6",
     "@types/express": "^4.17.6",
     "@types/file-saver": "^2.0.1",
     "@types/file-saver": "^2.0.1",
+    "@types/jest": "^27.0.2",
     "@types/js-cookie": "^2.2.6",
     "@types/js-cookie": "^2.2.6",
     "@types/moment-timezone": "^0.5.13",
     "@types/moment-timezone": "^0.5.13",
     "@types/react-collapse": "^5.0.0",
     "@types/react-collapse": "^5.0.0",
     "@types/react-dom": "^16.9.8",
     "@types/react-dom": "^16.9.8",
     "@types/react-modal": "^3.10.5",
     "@types/react-modal": "^3.10.5",
     "@types/react-notification-system": "^0.2.39",
     "@types/react-notification-system": "^0.2.39",
-    "@types/react-router-dom": "^5.1.5",
+    "@types/react-router-dom": "^5.1.2",
     "@types/react-tooltip": "^4.2.4",
     "@types/react-tooltip": "^4.2.4",
     "@types/styled-components": "^5.1.0",
     "@types/styled-components": "^5.1.0",
     "@typescript-eslint/eslint-plugin": "^5.6.0",
     "@typescript-eslint/eslint-plugin": "^5.6.0",
     "@typescript-eslint/parser": "^5.6.0",
     "@typescript-eslint/parser": "^5.6.0",
+    "cross-spawn": "^7.0.3",
     "cypress": "^3.2.0",
     "cypress": "^3.2.0",
     "eslint": "^8.2.0",
     "eslint": "^8.2.0",
     "eslint-config-airbnb": "19.0.0",
     "eslint-config-airbnb": "19.0.0",
@@ -41,6 +48,7 @@
     "eslint-plugin-jsx-a11y": "^6.5.1",
     "eslint-plugin-jsx-a11y": "^6.5.1",
     "eslint-plugin-react": "^7.27.0",
     "eslint-plugin-react": "^7.27.0",
     "eslint-plugin-react-hooks": "^4.3.0",
     "eslint-plugin-react-hooks": "^4.3.0",
+    "jest": "^27.3.1",
     "nodemon": "^2.0.4"
     "nodemon": "^2.0.4"
   },
   },
   "dependencies": {
   "dependencies": {
@@ -79,7 +87,7 @@
     "path": "^0.12.7",
     "path": "^0.12.7",
     "react": "^16.13.1",
     "react": "^16.13.1",
     "react-collapse": "^5.0.1",
     "react-collapse": "^5.0.1",
-    "react-datetime": "^2.10.3",
+    "react-datetime": "^3.1.1",
     "react-dom": "^16.13.1",
     "react-dom": "^16.13.1",
     "react-hot-loader": "^4.12.17",
     "react-hot-loader": "^4.12.17",
     "react-modal": "^3.11.2",
     "react-modal": "^3.11.2",
@@ -93,6 +101,7 @@
     "rimraf": "^2.6.2",
     "rimraf": "^2.6.2",
     "styled-components": "^4.4.1",
     "styled-components": "^4.4.1",
     "tai-password-strength": "^1.1.2",
     "tai-password-strength": "^1.1.2",
+    "ts-node": "10.4.0",
     "typescript": "^4.5.3",
     "typescript": "^4.5.3",
     "url-loader": "^4.1.0",
     "url-loader": "^4.1.0",
     "webpack": "^4.41.2",
     "webpack": "^4.41.2",
@@ -120,6 +129,6 @@
     "ua-parser-js": "^0.7.24",
     "ua-parser-js": "^0.7.24",
     "underscore": "^1.12.1",
     "underscore": "^1.12.1",
     "y18n": "^3.2.2",
     "y18n": "^3.2.2",
-    "yargs-parser": "^13.1.2"
+    "yargs-parser": "^20.2.9"
   }
   }
 }
 }

+ 0 - 16
private/jest/componentsMock.js

@@ -1,16 +0,0 @@
-// https://github.com/diegohaz/arc/wiki/Testing-components
-import React from 'react'
-import PropTypes from 'prop-types'
-
-module.exports = new Proxy({}, {
-  get: (target, property) => {
-    const Mock = props => React.createElement('span', null, props.children)
-
-    Mock.displayName = property
-    Mock.propTypes = {
-      children: PropTypes.any,
-    }
-
-    return Mock
-  },
-})

+ 0 - 1
private/jest/fileMock.js

@@ -1 +0,0 @@
-export default 'file'

+ 0 - 4
private/jest/setupTests.js

@@ -1,4 +0,0 @@
-import { configure } from 'enzyme'
-import Adapter from 'enzyme-adapter-react-16'
-
-configure({ adapter: new Adapter() })

+ 0 - 3
private/jest/shim.js

@@ -1,3 +0,0 @@
-global.requestAnimationFrame = /* istanbul ignore next */ (callback) => {
-  setTimeout(callback, 0)
-}

+ 13 - 2
src/components/App.tsx

@@ -120,6 +120,7 @@ class App extends React.Component<{}, State> {
     }) => (
     }) => (
       <Route
       <Route
         path={options.path}
         path={options.path}
+        // @ts-ignore
         exact={options.exact}
         exact={options.exact}
         render={() => (
         render={() => (
           <MessagePage
           <MessagePage
@@ -142,6 +143,7 @@ class App extends React.Component<{}, State> {
           showAuthAnimation: true,
           showAuthAnimation: true,
         })
         })
       }
       }
+      // @ts-ignore
       return <Route path={path} component={component} exact={exact} />
       return <Route path={path} component={component} exact={exact} />
     }
     }
 
 
@@ -173,6 +175,7 @@ class App extends React.Component<{}, State> {
         })
         })
       }
       }
       if (userStore.loggedUser?.isAdmin) {
       if (userStore.loggedUser?.isAdmin) {
+        // @ts-ignore
         return <Route path={actualPath} exact={exact} component={component} />
         return <Route path={actualPath} exact={exact} component={component} />
       }
       }
       return null
       return null
@@ -184,9 +187,14 @@ class App extends React.Component<{}, State> {
         <Router>
         <Router>
           <Switch>
           <Switch>
             {configLoader.isFirstLaunch ? (
             {configLoader.isFirstLaunch ? (
+            // @ts-ignore
               <Route path="/" component={SetupPage} exact />
               <Route path="/" component={SetupPage} exact />
+            // @ts-ignore
             ) : renderRoute('/', DashboardPage, true)}
             ) : renderRoute('/', DashboardPage, true)}
-            <Route path="/login" component={LoginPage} />
+            {
+              // @ts-ignore
+              <Route path="/login" component={LoginPage} />
+            }
             {renderRoute('/dashboard', DashboardPage)}
             {renderRoute('/dashboard', DashboardPage)}
             {renderRoute('/replicas', ReplicasPage, true)}
             {renderRoute('/replicas', ReplicasPage, true)}
             {renderRoute('/replicas/:id', ReplicaDetailsPage, true)}
             {renderRoute('/replicas/:id', ReplicaDetailsPage, true)}
@@ -208,7 +216,10 @@ class App extends React.Component<{}, State> {
             {renderOptionalRoute('projects', ProjectDetailsPage, '/projects/:id')}
             {renderOptionalRoute('projects', ProjectDetailsPage, '/projects/:id')}
             {renderOptionalRoute('logging', LogsPage)}
             {renderOptionalRoute('logging', LogsPage)}
             {renderRoute('/streamlog', LogStreamPage)}
             {renderRoute('/streamlog', LogStreamPage)}
-            <Route component={MessagePage} />
+            {
+              // @ts-ignore
+              <Route component={MessagePage} />
+            }
           </Switch>
           </Switch>
         </Router>
         </Router>
         <NotificationsModule />
         <NotificationsModule />

+ 99 - 0
src/components/modules/DashboardModule/DashboardActivity/DashboardActivity.spec.tsx

@@ -0,0 +1,99 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import { NotificationItemData } from '@src/@types/NotificationItem'
+import progressImage from '@src/components/ui/StatusComponents/StatusIcon/images/progress'
+import { ThemePalette } from '@src/components/Theme'
+import DashboardActivity from '.'
+
+const encodedProgressImage = encodeURIComponent(progressImage(ThemePalette.grayscale[3], ThemePalette.primary))
+
+jest.mock('react-router-dom', () => ({ Link: 'a' }))
+
+const ITEMS: NotificationItemData[] = [
+  {
+    id: '1',
+    type: 'replica',
+    status: 'ERROR',
+    name: 'Replica 1',
+    description: 'Replica 1 description',
+  },
+  {
+    id: '2',
+    type: 'migration',
+    status: 'RUNNING',
+    name: 'Migration 1',
+    description: 'Migration 1 description',
+  },
+  {
+    id: '3',
+    type: 'migration',
+    status: 'COMPLETED',
+    name: 'Migration 2',
+    description: 'Migration 2 description',
+  },
+]
+
+describe('DashboardActivity', () => {
+  it('renders no recent activity', () => {
+    render(<DashboardActivity notificationItems={[]} />)
+    expect(TestUtils.select('DashboardActivity__Message')!.textContent).toContain('There is no recent activity')
+  })
+
+  it('fires new click', () => {
+    const onNewClick = jest.fn()
+    render(<DashboardActivity notificationItems={[]} onNewClick={onNewClick} />)
+    TestUtils.select('Button__StyledButton')!.click()
+    expect(onNewClick).toHaveBeenCalled()
+  })
+
+  it('renders loading', () => {
+    const { rerender } = render(<DashboardActivity notificationItems={[]} loading />)
+    expect(TestUtils.select('DashboardActivity__LoadingWrapper')).toBeTruthy()
+
+    rerender(<DashboardActivity notificationItems={[]} />)
+    expect(TestUtils.select('DashboardActivity__LoadingWrapper')).toBeFalsy()
+  })
+
+  it('renders all items', () => {
+    render(<DashboardActivity notificationItems={ITEMS} />)
+
+    const listItemsEl = TestUtils.selectAll('DashboardActivity__ListItem')
+    expect(listItemsEl.length).toBe(ITEMS.length)
+  })
+
+  it.each`
+    idx  | href                     | expectedStatusIcon
+    ${0} | ${'/replicas/1'}         | ${'error-hollow.svg'}
+    ${1} | ${'/migrations/2/tasks'} | ${encodedProgressImage}
+    ${2} | ${'/migrations/3'}       | ${'success-hollow.svg'}
+  `('renders item with href $href', ({
+    idx, href, expectedStatusIcon,
+  }) => {
+    render(<DashboardActivity notificationItems={ITEMS} />)
+
+    const itemElement = TestUtils.selectAll('DashboardActivity__ListItem')[idx]
+    expect(itemElement.getAttribute('to')).toBe(href)
+
+    const background = window.getComputedStyle(TestUtils.select('StatusIcon__Wrapper', itemElement)!).background
+    expect(background).toContain(expectedStatusIcon)
+
+    expect(TestUtils.select('NotificationDropdown__ItemReplicaBadge', itemElement)!.textContent).toContain(ITEMS[idx].type === 'replica' ? 'RE' : 'MI')
+    expect(TestUtils.select('NotificationDropdown__ItemTitle', itemElement)!.textContent).toContain(ITEMS[idx].name)
+    expect(TestUtils.select('NotificationDropdown__ItemDescription', itemElement)!.textContent).toContain(ITEMS[idx].description)
+  })
+})

+ 4 - 4
src/components/modules/DashboardModule/DashboardActivity/DashboardActivity.tsx

@@ -87,10 +87,10 @@ const Message = styled.div<any>`
 
 
 type Props = {
 type Props = {
   notificationItems: NotificationItemData[],
   notificationItems: NotificationItemData[],
-  style: any,
-  loading: boolean,
-  large: boolean,
-  onNewClick: () => void,
+  style?: React.CSSProperties | null,
+  loading?: boolean,
+  large?: boolean,
+  onNewClick?: () => void,
 }
 }
 @observer
 @observer
 class DashboardActivity extends React.Component<Props> {
 class DashboardActivity extends React.Component<Props> {

+ 85 - 0
src/components/modules/DashboardModule/DashboardBarChart/DashboardBarChart.spec.tsx

@@ -0,0 +1,85 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import { ThemePalette } from '@src/components/Theme'
+import userEvent from '@testing-library/user-event'
+import DashboardBarChart from '.'
+
+const DATA: DashboardBarChart['props']['data'] = [
+  {
+    label: 'label 1',
+    values: [10, 15],
+    data: 'data 1',
+  },
+  {
+    label: 'label 2',
+    values: [20, 25],
+    data: 'data 2',
+  },
+]
+
+describe('DashboardBarChart', () => {
+  it('renders all data correctly', () => {
+    render(<DashboardBarChart data={DATA} yNumTicks={3} />)
+
+    // Y ticks
+
+    const yTickEl = TestUtils.selectAll('DashboardBarChart__YTick')
+    expect(yTickEl.length).toBe(3)
+    expect(yTickEl[0].textContent).toBe('0')
+    expect(yTickEl[1].textContent).toBe('20')
+    expect(yTickEl[2].textContent).toBe('40')
+
+    // Bars
+
+    const barsEl = TestUtils.selectAll('DashboardBarChart__Bar-')
+    expect(barsEl.length).toBe(DATA.length)
+    expect(barsEl[0].textContent).toBe('label 1')
+    expect(barsEl[1].textContent).toBe('label 2')
+  })
+
+  it.each`
+    barIndex | stackedBarIndex | expectedHeight                    | expectedColor
+    ${0}     | ${0}            | ${(DATA[0].values[1] / 45) * 100} | ${ThemePalette.alert}
+    ${0}     | ${1}            | ${(DATA[0].values[0] / 45) * 100} | ${ThemePalette.primary}
+    ${1}     | ${0}            | ${(DATA[1].values[1] / 45) * 100} | ${ThemePalette.alert}
+    ${1}     | ${1}            | ${(DATA[1].values[0] / 45) * 100} | ${ThemePalette.primary}
+  `('renders bar index $barIndex, stacked bar index $stackedBarIndex with height $expectedHeight and color $expectedColor', ({
+    barIndex, stackedBarIndex, expectedHeight, expectedColor,
+  }) => {
+    render(<DashboardBarChart data={DATA} yNumTicks={3} colors={[ThemePalette.alert, ThemePalette.primary]} />)
+
+    const stackedBarEl = TestUtils.selectAll('DashboardBarChart__StackedBar-', TestUtils.selectAll('DashboardBarChart__Bar-')[barIndex])[stackedBarIndex]
+    const style = window.getComputedStyle(stackedBarEl)
+
+    expect(parseFloat(style.height)).toBeCloseTo(expectedHeight)
+    expect(TestUtils.rgbToHex(style.background)).toBe(expectedColor)
+  })
+
+  it.each`
+  barIndex | stackedBarIndex | expectedData
+  ${0}     | ${0}            | ${DATA[0]}
+  ${0}     | ${1}            | ${DATA[0]}
+  ${1}     | ${0}            | ${DATA[1]}
+  ${1}     | ${1}            | ${DATA[1]}
+`('fires mouse position with correct data on bar mouse enter, bar index $barIndex, stacked bar index $stackedBarIndex', ({ barIndex, stackedBarIndex, expectedData }) => {
+    const onBarMouseEnter = jest.fn()
+    render(<DashboardBarChart data={DATA} yNumTicks={3} onBarMouseEnter={onBarMouseEnter} />)
+    userEvent.hover(TestUtils.selectAll('DashboardBarChart__StackedBar-', TestUtils.selectAll('DashboardBarChart__Bar-')[barIndex])[stackedBarIndex])
+    expect(onBarMouseEnter).toHaveBeenCalledWith({ x: 48, y: 65 }, expectedData)
+  })
+})

+ 2 - 4
src/components/modules/DashboardModule/DashboardBarChart/DashboardBarChart.tsx

@@ -16,7 +16,7 @@ import * as React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled from 'styled-components'
 import styled from 'styled-components'
 
 
-import { ThemeProps } from '@src/components/Theme'
+import { ThemePalette, ThemeProps } from '@src/components/Theme'
 import BarChartNiceScale from './BarChartNiceScale'
 import BarChartNiceScale from './BarChartNiceScale'
 
 
 const Wrapper = styled.div<any>`
 const Wrapper = styled.div<any>`
@@ -94,9 +94,7 @@ type DataItem = {
 }
 }
 type Props = {
 type Props = {
   style?: any,
   style?: any,
-  // eslint-disable-next-line react/no-unused-prop-types
   data: DataItem[],
   data: DataItem[],
-  // eslint-disable-next-line react/no-unused-prop-types
   yNumTicks: number,
   yNumTicks: number,
   colors?: string[],
   colors?: string[],
   onBarMouseEnter?: (position: { x: number, y: number }, item: DataItem) => void,
   onBarMouseEnter?: (position: { x: number, y: number }, item: DataItem) => void,
@@ -192,7 +190,7 @@ class DashboardBarChart extends React.Component<Props> {
                   <StackedBar
                   <StackedBar
                     // eslint-disable-next-line react/no-array-index-key
                     // eslint-disable-next-line react/no-array-index-key
                     key={`${item.label}-${i}`}
                     key={`${item.label}-${i}`}
-                    background={this.props.colors ? this.props.colors[i % this.props.colors.length] : '#0044CA'}
+                    background={this.props.colors ? this.props.colors[i % this.props.colors.length] : ThemePalette.primary}
                     height={height}
                     height={height}
                     onMouseEnter={(evt: MouseEvent) => {
                     onMouseEnter={(evt: MouseEvent) => {
                       const onMouseEnter = this.props.onBarMouseEnter
                       const onMouseEnter = this.props.onBarMouseEnter

+ 1 - 1
src/components/modules/DashboardModule/DashboardExecutions/DashboardExecutions.tsx

@@ -149,7 +149,7 @@ type State = {
   tooltipPosition: { x: number, y: number },
   tooltipPosition: { x: number, y: number },
   tooltipData: TooltipData | null,
   tooltipData: TooltipData | null,
 }
 }
-const COLORS = ['#F91661', '#0044CB']
+const COLORS = [ThemePalette.alert, ThemePalette.primary]
 
 
 @observer
 @observer
 class DashboardExecutions extends React.Component<Props, State> {
 class DashboardExecutions extends React.Component<Props, State> {

+ 1 - 2
src/components/modules/DetailsModule/DetailsContentHeader/DetailsContentHeader.tsx

@@ -126,7 +126,6 @@ class DetailsContentHeader extends React.Component<Props> {
         actions={this.props.dropdownActions}
         actions={this.props.dropdownActions}
         largeItems={this.props.largeDropdownActionItems}
         largeItems={this.props.largeDropdownActionItems}
         style={{ marginLeft: '32px' }}
         style={{ marginLeft: '32px' }}
-        data-test-id="dcHeader-actionButton"
       />
       />
     )
     )
   }
   }
@@ -144,7 +143,7 @@ class DetailsContentHeader extends React.Component<Props> {
   render() {
   render() {
     return (
     return (
       <Wrapper>
       <Wrapper>
-        <BackButton to={this.props.backLink} data-test-id="dcHeader-backButton" />
+        <BackButton to={this.props.backLink} />
         <TypeImage image={this.props.typeImage} />
         <TypeImage image={this.props.typeImage} />
         <Title>
         <Title>
           <Status>
           <Status>

+ 1 - 2
src/components/modules/EndpointModule/ChooseProvider/ChooseProvider.tsx

@@ -365,7 +365,6 @@ class ChooseProvider extends React.Component<Props, State> {
               height={128}
               height={128}
               key={k}
               key={k}
               endpoint={k}
               endpoint={k}
-              data-test-id={`cProvider-endpointLogo-${k}`}
               onClick={() => { this.props.onProviderClick(k) }}
               onClick={() => { this.props.onProviderClick(k) }}
             />
             />
           ))}
           ))}
@@ -384,7 +383,7 @@ class ChooseProvider extends React.Component<Props, State> {
           multiple
           multiple
           onChange={e => { this.handleFileUpload(e.target.files) }}
           onChange={e => { this.handleFileUpload(e.target.files) }}
         />
         />
-        <Button secondary onClick={this.props.onCancelClick} data-test-id="cProvider-cancelButton">Cancel</Button>
+        <Button secondary onClick={this.props.onCancelClick}>Cancel</Button>
       </Providers>
       </Providers>
     )
     )
   }
   }

+ 11 - 11
src/components/modules/EndpointModule/EndpointDetailsContent/EndpointDetailsContent.tsx

@@ -130,7 +130,7 @@ class EndpointDetailsContent extends React.Component<Props> {
 
 
     return (
     return (
       <LoadingWrapper>
       <LoadingWrapper>
-        <StatusImage loading data-test-id="edContent-connLoading" />
+        <StatusImage loading />
       </LoadingWrapper>
       </LoadingWrapper>
     )
     )
   }
   }
@@ -169,11 +169,11 @@ class EndpointDetailsContent extends React.Component<Props> {
       const schemaField = this.props.connectionInfoSchema.find(f => f.name === key)
       const schemaField = this.props.connectionInfoSchema.find(f => f.name === key)
 
 
       if (configLoader.config.passwordFields.find(fn => fn === key) || key.indexOf('password') > -1) {
       if (configLoader.config.passwordFields.find(fn => fn === key) || key.indexOf('password') > -1) {
-        valueElement = <PasswordValue value={value} data-test-id="edContent-connPassword" />
+        valueElement = <PasswordValue value={value} />
       } else if (schemaField?.useFile) {
       } else if (schemaField?.useFile) {
         valueElement = this.renderDownloadValue(value, key)
         valueElement = this.renderDownloadValue(value, key)
       } else {
       } else {
-        valueElement = this.renderValue(value, `connValue-${key}`)
+        valueElement = this.renderValue(value)
       }
       }
 
 
       return (
       return (
@@ -189,17 +189,17 @@ class EndpointDetailsContent extends React.Component<Props> {
     return (
     return (
       <Buttons>
       <Buttons>
         <MainButtons>
         <MainButtons>
-          <Button onClick={this.props.onValidateClick} data-test-id="edContent-validateButton">Validate Endpoint</Button>
+          <Button onClick={this.props.onValidateClick}>Validate Endpoint</Button>
         </MainButtons>
         </MainButtons>
         <DeleteButton>
         <DeleteButton>
-          <Button hollow alert onClick={this.props.onDeleteClick} data-test-id="edContent-deleteButton">Delete Endpoint</Button>
+          <Button hollow alert onClick={this.props.onDeleteClick}>Delete Endpoint</Button>
         </DeleteButton>
         </DeleteButton>
       </Buttons>
       </Buttons>
     )
     )
   }
   }
 
 
-  renderValue(value: string, dataTestId?: string) {
-    return <CopyValue data-test-id={dataTestId ? `edContent-${dataTestId}` : undefined} value={value} maxWidth="90%" />
+  renderValue(value: string) {
+    return <CopyValue value={value} maxWidth="90%" />
   }
   }
 
 
   renderRegions() {
   renderRegions() {
@@ -246,11 +246,11 @@ class EndpointDetailsContent extends React.Component<Props> {
           </Field>
           </Field>
           <Field>
           <Field>
             <Label>Name</Label>
             <Label>Name</Label>
-            {this.renderValue(name || '', 'name')}
+            {this.renderValue(name || '')}
           </Field>
           </Field>
           <Field>
           <Field>
             <Label>Type</Label>
             <Label>Type</Label>
-            {this.renderValue(this.props.item ? configLoader.config.providerNames[this.props.item.type] : '', 'type')}
+            {this.renderValue(this.props.item ? configLoader.config.providerNames[this.props.item.type] : '')}
           </Field>
           </Field>
           <Field>
           <Field>
             <Label>Coriolis Regions</Label>
             <Label>Coriolis Regions</Label>
@@ -258,11 +258,11 @@ class EndpointDetailsContent extends React.Component<Props> {
           </Field>
           </Field>
           <Field>
           <Field>
             <Label>Description</Label>
             <Label>Description</Label>
-            {description ? <CopyMultilineValue data-test-id="edContent-description" value={description} /> : <Value>-</Value>}
+            {description ? <CopyMultilineValue value={description} /> : <Value>-</Value>}
           </Field>
           </Field>
           <Field>
           <Field>
             <Label>Created</Label>
             <Label>Created</Label>
-            {this.renderValue(DateUtils.getLocalTime(created_at).format('DD/MM/YYYY HH:mm'), 'created')}
+            {this.renderValue(DateUtils.getLocalTime(created_at).format('DD/MM/YYYY HH:mm'))}
           </Field>
           </Field>
           <Field>
           <Field>
             <Label>Used in replicas/migrations ({usage.length})</Label>
             <Label>Used in replicas/migrations ({usage.length})</Label>

+ 1 - 4
src/components/modules/EndpointModule/EndpointDuplicateOptions/EndpointDuplicateOptions.tsx

@@ -84,7 +84,6 @@ type Props = {
 type State = {
 type State = {
   selectedProjectId: string,
   selectedProjectId: string,
 }
 }
-const testName = 'edOptions'
 @observer
 @observer
 class EndpointDuplicateOptions extends React.Component<Props, State> {
 class EndpointDuplicateOptions extends React.Component<Props, State> {
   UNSAFE_componentWillMount() {
   UNSAFE_componentWillMount() {
@@ -103,7 +102,7 @@ class EndpointDuplicateOptions extends React.Component<Props, State> {
 
 
   renderDuplicating() {
   renderDuplicating() {
     return (
     return (
-      <Loading data-test-id={`${testName}-loading`}>
+      <Loading>
         <StatusImage loading />
         <StatusImage loading />
         <Message>
         <Message>
           <Title>Duplicating Endpoint</Title>
           <Title>Duplicating Endpoint</Title>
@@ -119,7 +118,6 @@ class EndpointDuplicateOptions extends React.Component<Props, State> {
         <Image />
         <Image />
         <Form>
         <Form>
           <FieldInputStyled
           <FieldInputStyled
-            data-test-id={`${testName}-field-project`}
             name="duplicate_to_project"
             name="duplicate_to_project"
             label="Duplicate To Project"
             label="Duplicate To Project"
             type="string"
             type="string"
@@ -133,7 +131,6 @@ class EndpointDuplicateOptions extends React.Component<Props, State> {
         <Buttons>
         <Buttons>
           <Button secondary onClick={this.props.onCancelClick}>Cancel</Button>
           <Button secondary onClick={this.props.onCancelClick}>Cancel</Button>
           <Button
           <Button
-            data-test-id={`${testName}-duplicateButton`}
             onClick={() => { this.props.onDuplicateClick(this.state.selectedProjectId) }}
             onClick={() => { this.props.onDuplicateClick(this.state.selectedProjectId) }}
           >Duplicate
           >Duplicate
           </Button>
           </Button>

+ 4 - 5
src/components/modules/EndpointModule/EndpointListItem/EndpointListItem.tsx

@@ -103,15 +103,14 @@ class EndpointListItem extends React.Component<Props> {
     return (
     return (
       <Wrapper>
       <Wrapper>
         <CheckboxStyled
         <CheckboxStyled
-          data-test-id={`endpointListItem-checkbox-${this.props.item.name}`}
           checked={this.props.selected}
           checked={this.props.selected}
           onChange={this.props.onSelectedChange}
           onChange={this.props.onSelectedChange}
         />
         />
-        <Content onClick={this.props.onClick} data-test-id={`endpointListItem-content-${this.props.item.name}`}>
+        <Content onClick={this.props.onClick}>
           <Image image={endpointImage} />
           <Image image={endpointImage} />
           <Title>
           <Title>
-            <TitleLabel data-test-id="endpointListItem-name">{this.props.item.name}</TitleLabel>
-            <Subtitle data-test-id="endpointListItem-description">{this.props.item.description || 'N/A'}</Subtitle>
+            <TitleLabel>{this.props.item.name}</TitleLabel>
+            <Subtitle>{this.props.item.description || 'N/A'}</Subtitle>
           </Title>
           </Title>
           <EndpointLogos height={42} endpoint={this.props.item.type} />
           <EndpointLogos height={42} endpoint={this.props.item.type} />
           <Created>
           <Created>
@@ -122,7 +121,7 @@ class EndpointListItem extends React.Component<Props> {
           </Created>
           </Created>
           <Usage>
           <Usage>
             <ItemLabel>Usage</ItemLabel>
             <ItemLabel>Usage</ItemLabel>
-            <ItemValue data-test-id="endpointListItem-usageCount">
+            <ItemValue>
               {this.props.getUsage(this.props.item).migrationsCount} migrations,&nbsp;
               {this.props.getUsage(this.props.item).migrationsCount} migrations,&nbsp;
               {this.props.getUsage(this.props.item).replicasCount} replicas
               {this.props.getUsage(this.props.item).replicasCount} replicas
             </ItemValue>
             </ItemValue>

+ 1 - 4
src/components/modules/EndpointModule/EndpointLogos/EndpointLogos.tsx

@@ -42,7 +42,6 @@ type Props = {
   white?: boolean,
   white?: boolean,
   baseUrl?: string,
   baseUrl?: string,
   onClick?: () => void
   onClick?: () => void
-  'data-test-id'?: string,
   style?: React.CSSProperties
   style?: React.CSSProperties
 }
 }
 @observer
 @observer
@@ -54,7 +53,6 @@ class EndpointLogos extends React.Component<Props> {
   renderGenericLogo(size: { w: number, h: number }) {
   renderGenericLogo(size: { w: number, h: number }) {
     return (
     return (
       <Generic
       <Generic
-        data-test-id="endpointLogos-genericLogo"
         size={size}
         size={size}
         name={this.props.endpoint || ''}
         name={this.props.endpoint || ''}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
@@ -80,12 +78,11 @@ class EndpointLogos extends React.Component<Props> {
 
 
     return (
     return (
       // eslint-disable-next-line react/jsx-props-no-spreading
       // eslint-disable-next-line react/jsx-props-no-spreading
-      <Wrapper {...this.props} data-test-id={this.props['data-test-id'] || 'endpointLogos'}>
+      <Wrapper {...this.props}>
         <Logo
         <Logo
           width={size.w}
           width={size.w}
           height={size.h}
           height={size.h}
           url={imageUrl}
           url={imageUrl}
-          data-test-id="endpointLogos-logo"
         >
         >
           {imageUrl ? null : this.renderGenericLogo(size)}
           {imageUrl ? null : this.renderGenericLogo(size)}
         </Logo>
         </Logo>

+ 1 - 1
src/components/modules/EndpointModule/EndpointModal/EndpointModal.tsx

@@ -388,7 +388,7 @@ class EndpointModal extends React.Component<Props, State> {
     }
     }
 
 
     return (
     return (
-      <Status data-test-id="endpointStatus">
+      <Status>
         <StatusHeader>
         <StatusHeader>
           <StatusIcon status={status} />
           <StatusIcon status={status} />
           <StatusMessage>{message}{showErrorButton}</StatusMessage>
           <StatusMessage>{message}{showErrorButton}</StatusMessage>

+ 7 - 7
src/components/modules/EndpointModule/EndpointValidation/EndpointValidation.tsx

@@ -96,9 +96,9 @@ class EndpointValidation extends React.Component<Props> {
 
 
     return (
     return (
       <Loading>
       <Loading>
-        <StatusImage loading data-test-id="eValidation-status" />
+        <StatusImage loading />
         <Message>
         <Message>
-          <Title data-test-id="eValidation-title">Validating Endpoint</Title>
+          <Title>Validating Endpoint</Title>
           <Subtitle>Please wait ...</Subtitle>
           <Subtitle>Please wait ...</Subtitle>
         </Message>
         </Message>
       </Loading>
       </Loading>
@@ -112,9 +112,9 @@ class EndpointValidation extends React.Component<Props> {
 
 
     return (
     return (
       <Validation>
       <Validation>
-        <StatusImage status="COMPLETED" data-test-id="eValidation-status" />
+        <StatusImage status="COMPLETED" />
         <Message>
         <Message>
-          <Title data-test-id="eValidation-title">Endpoint is Valid</Title>
+          <Title>Endpoint is Valid</Title>
           <Subtitle>All tests passed succesfully.</Subtitle>
           <Subtitle>All tests passed succesfully.</Subtitle>
         </Message>
         </Message>
       </Validation>
       </Validation>
@@ -130,10 +130,10 @@ class EndpointValidation extends React.Component<Props> {
 
 
     return (
     return (
       <Validation>
       <Validation>
-        <StatusImage status="ERROR" data-test-id="eValidation-status" />
+        <StatusImage status="ERROR" />
         <Message>
         <Message>
-          <Title data-test-id="eValidation-title">Validation Failed</Title>
-          <Error onClick={() => { this.handleCopyClick(message) }} data-test-id="eValidation-errorMessage">
+          <Title>Validation Failed</Title>
+          <Error onClick={() => { this.handleCopyClick(message) }}>
             {message}<CopyButton />
             {message}<CopyButton />
           </Error>
           </Error>
         </Message>
         </Message>

+ 0 - 3
src/components/modules/LoginModule/LoginForm/LoginForm.tsx

@@ -152,7 +152,6 @@ class LoginForm extends React.Component<Props, State> {
       <LoginError>
       <LoginError>
         <LoginErrorIcon />
         <LoginErrorIcon />
         <LoginErrorText
         <LoginErrorText
-          data-test-id="loginForm-errorText"
           dangerouslySetInnerHTML={{ __html: errorMessage }}
           dangerouslySetInnerHTML={{ __html: errorMessage }}
         />
         />
       </LoginError>
       </LoginError>
@@ -191,7 +190,6 @@ class LoginForm extends React.Component<Props, State> {
             value={this.state.username}
             value={this.state.username}
             name="username"
             name="username"
             onChange={e => { this.handleUsernameChange(e.target.value) }}
             onChange={e => { this.handleUsernameChange(e.target.value) }}
-            data-test-id="loginForm-usernameField"
           />
           />
           <LoginFormField
           <LoginFormField
             label="Password"
             label="Password"
@@ -199,7 +197,6 @@ class LoginForm extends React.Component<Props, State> {
             onChange={e => { this.handlePasswordChange(e.target.value) }}
             onChange={e => { this.handlePasswordChange(e.target.value) }}
             name="password"
             name="password"
             type="password"
             type="password"
-            data-test-id="loginForm-passwordField"
           />
           />
         </FormFields>
         </FormFields>
         {button}
         {button}

+ 1 - 2
src/components/modules/LoginModule/LoginFormField/LoginFormField.tsx

@@ -42,9 +42,8 @@ type Props = {
 }
 }
 const LoginFormField = (props: Props) => (
 const LoginFormField = (props: Props) => (
   <Wrapper>
   <Wrapper>
-    <FormFieldLabel data-test-id="loginFormField-label">{props.label}</FormFieldLabel>
+    <FormFieldLabel>{props.label}</FormFieldLabel>
     <StyledTextInput
     <StyledTextInput
-      data-test-id="loginFormField-input"
       // eslint-disable-next-line react/jsx-props-no-spreading
       // eslint-disable-next-line react/jsx-props-no-spreading
       {...props}
       {...props}
       onChange={props.onChange}
       onChange={props.onChange}

+ 1 - 2
src/components/modules/LoginModule/LoginOptions/LoginOptions.tsx

@@ -105,11 +105,10 @@ const LoginOptions = (props: Props) => {
     <Wrapper>
     <Wrapper>
       {buttons.map(button => (
       {buttons.map(button => (
         <Button
         <Button
-          data-test-id={`loginOptions-button-${button.id}`}
           key={button.id}
           key={button.id}
           id={button.id}
           id={button.id}
         >
         >
-          <Logo data-test-id={`loginOptions-logo-${button.id}`} id={button.id} />Sign in with {button.name}
+          <Logo id={button.id} />Sign in with {button.name}
         </Button>
         </Button>
       ))}
       ))}
     </Wrapper>
     </Wrapper>

+ 1 - 1
src/components/modules/NavigationModule/DetailsNavigation/test.tsx

@@ -26,7 +26,7 @@ const items = [
 
 
 describe('DetailsNavigation Component', () => {
 describe('DetailsNavigation Component', () => {
   // it('renders 3 items', () => {
   // it('renders 3 items', () => {
-  //   let wrapper = wrap({ items, 'data-test-id': 'dn-wrapper' })
+  //   let wrapper = wrap({ items})
   //   console.log(wrapper.find('dn-wrapper').debug())
   //   console.log(wrapper.find('dn-wrapper').debug())
   //   // items.forEach(item => {
   //   // items.forEach(item => {
   //   //   expect(wrapper.find(item.value).shallow.dive().dive()).toBe(item.label)
   //   //   expect(wrapper.find(item.value).shallow.dive().dive()).toBe(item.label)

+ 0 - 2
src/components/modules/NavigationModule/Navigation/Navigation.tsx

@@ -356,7 +356,6 @@ class Navigation extends React.Component<Props> {
               key={item.value}
               key={item.value}
               selected={this.props.currentPage === item.value}
               selected={this.props.currentPage === item.value}
               to={`/${item.value}`}
               to={`/${item.value}`}
-              data-test-id={`navigation-item-${item.value}`}
             >{item.label}
             >{item.label}
             </MenuItem>
             </MenuItem>
           ))
           ))
@@ -416,7 +415,6 @@ class Navigation extends React.Component<Props> {
                 key={item.value}
                 key={item.value}
                 selected={this.props.currentPage === item.value}
                 selected={this.props.currentPage === item.value}
                 to={`/${item.value}`}
                 to={`/${item.value}`}
-                data-test-id={`${TEST_ID}-smallMenuItem-${item.value}`}
               >
               >
                 <SmallMenuBackground />
                 <SmallMenuBackground />
                 {bullet ? <SmallMenuItemBullet bullet={bullet} /> : null}
                 {bullet ? <SmallMenuItemBullet bullet={bullet} /> : null}

+ 0 - 1
src/components/modules/NavigationModule/NavigationMini/NavigationMini.tsx

@@ -78,7 +78,6 @@ class NavigationMini extends React.Component<{}, State> {
           open={this.state.open}
           open={this.state.open}
           onClick={() => { this.handleMenuToggleClick() }}
           onClick={() => { this.handleMenuToggleClick() }}
           dangerouslySetInnerHTML={{ __html: menuImage() }}
           dangerouslySetInnerHTML={{ __html: menuImage() }}
-          data-test-id={`${TEST_ID}-toggleButton`}
         />
         />
         {this.state.open ? <Stub /> : null}
         {this.state.open ? <Stub /> : null}
         <NavigationStyled
         <NavigationStyled

+ 3 - 9
src/components/modules/ProjectModule/ProjectDetailsContent/ProjectDetailsContent.tsx

@@ -105,7 +105,6 @@ type Props = {
 type State = {
 type State = {
   showRemoveUserAlert: boolean,
   showRemoveUserAlert: boolean,
 }
 }
-const testName = 'pdContent'
 @observer
 @observer
 class ProjectDetailsContent extends React.Component<Props, State> {
 class ProjectDetailsContent extends React.Component<Props, State> {
   state = {
   state = {
@@ -185,7 +184,7 @@ class ProjectDetailsContent extends React.Component<Props, State> {
       <Info>
       <Info>
         <Field>
         <Field>
           <Label>Name</Label>
           <Label>Name</Label>
-          {this.renderValue(project.name, 'name')}
+          {this.renderValue(project.name)}
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>Description</Label>
           <Label>Description</Label>
@@ -197,7 +196,7 @@ class ProjectDetailsContent extends React.Component<Props, State> {
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>ID</Label>
           <Label>ID</Label>
-          {this.renderValue(project.id, 'id')}
+          {this.renderValue(project.id)}
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>Enabled</Label>
           <Label>Enabled</Label>
@@ -238,13 +237,11 @@ class ProjectDetailsContent extends React.Component<Props, State> {
       const userRoles = getUserRoles(user)
       const userRoles = getUserRoles(user)
       const columns = [
       const columns = [
         <UserName
         <UserName
-          data-test-id={`pdContent-users-${user.name}`}
           disabled={!user.enabled}
           disabled={!user.enabled}
           to={`/users/${user.id}`}
           to={`/users/${user.id}`}
         >{user.name}
         >{user.name}
         </UserName>,
         </UserName>,
         <DropdownLink
         <DropdownLink
-          data-test-id={`${testName}-roles-${user.name}`}
           width="214px"
           width="214px"
           getLabel={() => (userRoles.length > 0 ? userRoles.map(r => r.label).join(', ') : 'No roles')}
           getLabel={() => (userRoles.length > 0 ? userRoles.map(r => r.label).join(', ') : 'No roles')}
           selectedItems={userRoles.map(r => r.value)}
           selectedItems={userRoles.map(r => r.value)}
@@ -264,7 +261,6 @@ class ProjectDetailsContent extends React.Component<Props, State> {
         />,
         />,
         <UserColumn disabled={!user.enabled}>{user.enabled ? 'Enabled' : 'Disabled'}</UserColumn>,
         <UserColumn disabled={!user.enabled}>{user.enabled ? 'Enabled' : 'Disabled'}</UserColumn>,
         <DropdownLink
         <DropdownLink
-          data-test-id={`${testName}-actions-${user.name}`}
           noCheckmark
           noCheckmark
           width="82px"
           width="82px"
           items={userActions}
           items={userActions}
@@ -282,7 +278,6 @@ class ProjectDetailsContent extends React.Component<Props, State> {
 
 
     return (
     return (
       <TableStyled
       <TableStyled
-        data-test-id={`${testName}-members`}
         header={['Member', 'Roles', 'Status', '']}
         header={['Member', 'Roles', 'Status', '']}
         items={rows}
         items={rows}
         noItemsLabel="No members available!"
         noItemsLabel="No members available!"
@@ -291,10 +286,9 @@ class ProjectDetailsContent extends React.Component<Props, State> {
     )
     )
   }
   }
 
 
-  renderValue(value: string, dataTestId: string) {
+  renderValue(value: string) {
     return value !== '-' ? (
     return value !== '-' ? (
       <CopyValue
       <CopyValue
-        data-test-id={`${testName}-${dataTestId}`}
         value={value}
         value={value}
         maxWidth="90%"
         maxWidth="90%"
       />
       />

+ 0 - 2
src/components/modules/ProjectModule/ProjectDetailsContent/test.tsx

@@ -71,10 +71,8 @@ describe('ProjectDetailsContent Component', () => {
     expect(wrapper.find('name').prop('value')).toBe('Project 1')
     expect(wrapper.find('name').prop('value')).toBe('Project 1')
     expect(wrapper.find('id').prop('value')).toBe('project-1')
     expect(wrapper.find('id').prop('value')).toBe('project-1')
     let rows = wrapper.find('members').prop('items')
     let rows = wrapper.find('members').prop('items')
-    expect(rows[0][0].props['data-test-id']).toBe('pdContent-users-User 1')
     expect(rows[0][1].props.selectedItems.length).toBe(1)
     expect(rows[0][1].props.selectedItems.length).toBe(1)
     expect(rows[0][1].props.selectedItems[0]).toBe('role-1')
     expect(rows[0][1].props.selectedItems[0]).toBe('role-1')
-    expect(rows[1][0].props['data-test-id']).toBe('pdContent-users-User 2')
     expect(rows[1][1].props.selectedItems.length).toBe(1)
     expect(rows[1][1].props.selectedItems.length).toBe(1)
     expect(rows[1][1].props.selectedItems[0]).toBe('role-2')
     expect(rows[1][1].props.selectedItems[0]).toBe('role-2')
   })
   })

+ 5 - 7
src/components/modules/ProjectModule/ProjectListItem/ProjectListItem.tsx

@@ -96,7 +96,6 @@ type Props = {
   isCurrentProject: (projectId: string) => boolean,
   isCurrentProject: (projectId: string) => boolean,
   onSwitchProjectClick: (projectId: string) => void | Promise<void>,
   onSwitchProjectClick: (projectId: string) => void | Promise<void>,
 }
 }
-const testName = 'plItem'
 @observer
 @observer
 class ProjectListItem extends React.Component<Props> {
 class ProjectListItem extends React.Component<Props> {
   render() {
   render() {
@@ -104,22 +103,22 @@ class ProjectListItem extends React.Component<Props> {
 
 
     return (
     return (
       <Wrapper>
       <Wrapper>
-        <Content onClick={this.props.onClick} data-test-id={`${testName}-content`}>
+        <Content onClick={this.props.onClick}>
           <Image />
           <Image />
           <Title>
           <Title>
-            <TitleLabel data-test-id={`${testName}-name`}>{this.props.item.name}</TitleLabel>
-            <Subtitle data-test-id={`${testName}-description`}>{this.props.item.description}</Subtitle>
+            <TitleLabel>{this.props.item.name}</TitleLabel>
+            <Subtitle>{this.props.item.description}</Subtitle>
           </Title>
           </Title>
           <Body>
           <Body>
             <Data percentage={33}>
             <Data percentage={33}>
               <ItemLabel>Members</ItemLabel>
               <ItemLabel>Members</ItemLabel>
-              <ItemValue data-test-id={`${testName}-members`}>
+              <ItemValue>
                 {this.props.getMembers(this.props.item.id)}
                 {this.props.getMembers(this.props.item.id)}
               </ItemValue>
               </ItemValue>
             </Data>
             </Data>
             <Data percentage={33}>
             <Data percentage={33}>
               <ItemLabel>Enabled</ItemLabel>
               <ItemLabel>Enabled</ItemLabel>
-              <ItemValue data-test-id={`${testName}-enabled`}>
+              <ItemValue>
                 {this.props.item.enabled ? 'Yes' : 'No'}
                 {this.props.item.enabled ? 'Yes' : 'No'}
               </ItemValue>
               </ItemValue>
             </Data>
             </Data>
@@ -134,7 +133,6 @@ class ProjectListItem extends React.Component<Props> {
                   if (e) e.stopPropagation(); this.props.onSwitchProjectClick(this.props.item.id)
                   if (e) e.stopPropagation(); this.props.onSwitchProjectClick(this.props.item.id)
                 }}
                 }}
                 disabled={isCurrentProject}
                 disabled={isCurrentProject}
-                data-test-id={`${testName}-currentButton`}
               >{isCurrentProject ? 'Current' : 'Switch'}
               >{isCurrentProject ? 'Current' : 'Switch'}
               </Button>
               </Button>
             </Data>
             </Data>

+ 0 - 6
src/components/modules/ProjectModule/ProjectMemberModal/ProjectMemberModal.tsx

@@ -99,7 +99,6 @@ type State = {
   selectedRolesExisting: string[],
   selectedRolesExisting: string[],
   selectedRolesNew: string[],
   selectedRolesNew: string[],
 }
 }
-const testName = 'pmModal'
 @observer
 @observer
 class ProjectMemberModal extends React.Component<Props, State> {
 class ProjectMemberModal extends React.Component<Props, State> {
   state: State = {
   state: State = {
@@ -204,7 +203,6 @@ class ProjectMemberModal extends React.Component<Props, State> {
     }]
     }]
     return (
     return (
       <ToggleButtonBarStyled
       <ToggleButtonBarStyled
-        data-test-id={`${testName}-formToggle`}
         items={items}
         items={items}
         selectedValue={this.state.isNew ? 'new' : 'existing'}
         selectedValue={this.state.isNew ? 'new' : 'existing'}
         onChange={item => { this.setState({ isNew: item.value === 'new' }) }}
         onChange={item => { this.setState({ isNew: item.value === 'new' }) }}
@@ -226,7 +224,6 @@ class ProjectMemberModal extends React.Component<Props, State> {
 
 
     return (
     return (
       <FieldInput
       <FieldInput
-        data-test-id={`${testName}-roles`}
         key="roles"
         key="roles"
         name="role(s)"
         name="role(s)"
         label="Role(s)"
         label="Role(s)"
@@ -254,7 +251,6 @@ class ProjectMemberModal extends React.Component<Props, State> {
   renderField(field: FieldType, value: any, onChange: (value: any) => void) {
   renderField(field: FieldType, value: any, onChange: (value: any) => void) {
     return (
     return (
       <FieldStyled
       <FieldStyled
-        data-test-id={`${testName}-field-${field.name}`}
         key={field.name}
         key={field.name}
         name={field.name}
         name={field.name}
         type={field.type || 'string'}
         type={field.type || 'string'}
@@ -336,7 +332,6 @@ class ProjectMemberModal extends React.Component<Props, State> {
             Username
             Username
           </FormLabel>
           </FormLabel>
           <AutocompleteDropdown
           <AutocompleteDropdown
-            data-test-id={`${testName}-users`}
             items={users}
             items={users}
             disabled={this.props.loading}
             disabled={this.props.loading}
             selectedItem={this.state.selectedUser ? this.state.selectedUser.id : ''}
             selectedItem={this.state.selectedUser ? this.state.selectedUser.id : ''}
@@ -381,7 +376,6 @@ class ProjectMemberModal extends React.Component<Props, State> {
               large
               large
               disabled={this.props.loading}
               disabled={this.props.loading}
               onClick={() => { this.handleAddClick() }}
               onClick={() => { this.handleAddClick() }}
-              data-test-id={`${testName}-addButton`}
             >Add Member
             >Add Member
             </Button>
             </Button>
           </Buttons>
           </Buttons>

+ 0 - 3
src/components/modules/ProjectModule/ProjectModal/ProjectModal.tsx

@@ -66,7 +66,6 @@ type State = {
   highlightFieldNames: string[],
   highlightFieldNames: string[],
   description?: string,
   description?: string,
 }
 }
-const testName = 'projectModal'
 @observer
 @observer
 class ProjectModal extends React.Component<Props, State> {
 class ProjectModal extends React.Component<Props, State> {
   UNSAFE_componentWillMount() {
   UNSAFE_componentWillMount() {
@@ -118,7 +117,6 @@ class ProjectModal extends React.Component<Props, State> {
     return (
     return (
       <FieldInput
       <FieldInput
         layout="modal"
         layout="modal"
-        data-test-id={`${testName}-field-${field.name}`}
         key={field.name}
         key={field.name}
         name={field.name}
         name={field.name}
         type={field.type || 'string'}
         type={field.type || 'string'}
@@ -179,7 +177,6 @@ class ProjectModal extends React.Component<Props, State> {
             >Cancel
             >Cancel
             </Button>
             </Button>
             <Button
             <Button
-              data-test-id={`${testName}-updateButton`}
               large
               large
               disabled={this.props.loading}
               disabled={this.props.loading}
               onClick={() => { this.handleUpdateClick() }}
               onClick={() => { this.handleUpdateClick() }}

+ 3 - 4
src/components/modules/TransferModule/Executions/Executions.tsx

@@ -259,7 +259,6 @@ class Executions extends React.Component<Props, State> {
         onPreviousClick={() => { this.handlePreviousExecutionClick() }}
         onPreviousClick={() => { this.handlePreviousExecutionClick() }}
         onNextClick={() => { this.handleNextExecutionClick() }}
         onNextClick={() => { this.handleNextExecutionClick() }}
         onItemClick={item => { this.handleTimelineItemClick(item) }}
         onItemClick={item => { this.handleTimelineItemClick(item) }}
-        data-test-id="executions-timeline"
       />
       />
     )
     )
   }
   }
@@ -312,7 +311,7 @@ class Executions extends React.Component<Props, State> {
 
 
     return (
     return (
       <ExecutionInfo>
       <ExecutionInfo>
-        <ExecutionInfoNumber data-test-id="executions-number">Execution #{this.state.selectedExecution.number}</ExecutionInfoNumber>
+        <ExecutionInfoNumber>Execution #{this.state.selectedExecution.number}</ExecutionInfoNumber>
         <StatusPill style={{ marginRight: '16px' }} small status={this.state.selectedExecution.status} />
         <StatusPill style={{ marginRight: '16px' }} small status={this.state.selectedExecution.status} />
         <ExecutionInfoDate>
         <ExecutionInfoDate>
           {DateUtils.getLocalTime(this.state.selectedExecution.created_at).format('DD MMMM YYYY HH:mm')}
           {DateUtils.getLocalTime(this.state.selectedExecution.created_at).format('DD MMMM YYYY HH:mm')}
@@ -350,9 +349,9 @@ class Executions extends React.Component<Props, State> {
     return (
     return (
       <NoExecutions>
       <NoExecutions>
         <ExecutionImage />
         <ExecutionImage />
-        <NoExecutionTitle data-test-id="executions-noExTitle">It looks like there are no executions in this replica.</NoExecutionTitle>
+        <NoExecutionTitle>It looks like there are no executions in this replica.</NoExecutionTitle>
         <NoExecutionText>This replica has not been executed yet.</NoExecutionText>
         <NoExecutionText>This replica has not been executed yet.</NoExecutionText>
-        <Button onClick={this.props.onExecuteClick} data-test-id="executions-executeButton">Execute Now</Button>
+        <Button onClick={this.props.onExecuteClick}>Execute Now</Button>
       </NoExecutions>
       </NoExecutions>
     )
     )
   }
   }

+ 7 - 9
src/components/modules/TransferModule/MainDetails/MainDetails.tsx

@@ -169,13 +169,13 @@ class MainDetails extends React.Component<Props, State> {
     return this.props.item ? this.renderValue(DateUtils.getLocalTime(this.props.item.updated_at).format('YYYY-MM-DD HH:mm:ss')) : '-'
     return this.props.item ? this.renderValue(DateUtils.getLocalTime(this.props.item.updated_at).format('YYYY-MM-DD HH:mm:ss')) : '-'
   }
   }
 
 
-  renderValue(value: string, dateTestId?: string) {
-    return <CopyValue value={value} maxWidth="90%" data-test-id={dateTestId ? `mainDetails-${dateTestId}` : undefined} />
+  renderValue(value: string) {
+    return <CopyValue value={value} maxWidth="90%" />
   }
   }
 
 
   renderEndpointLink(type: string): React.ReactNode {
   renderEndpointLink(type: string): React.ReactNode {
     const endpointIsMissing = (
     const endpointIsMissing = (
-      <Value flex data-test-id={`mainDetails-missing-${type}`}>
+      <Value flex>
         <StatusIcon style={{ marginRight: '8px' }} status="ERROR" />Endpoint is missing
         <StatusIcon style={{ marginRight: '8px' }} status="ERROR" />Endpoint is missing
       </Value>
       </Value>
     )
     )
@@ -289,7 +289,6 @@ class MainDetails extends React.Component<Props, State> {
           <Row>
           <Row>
             <EndpointLogos
             <EndpointLogos
               endpoint={(sourceEndpoint ? sourceEndpoint.type : '') as any}
               endpoint={(sourceEndpoint ? sourceEndpoint.type : '') as any}
-              data-test-id="mainDetails-sourceLogo"
             />
             />
           </Row>
           </Row>
           {getPropertyNames('source').length > 0 ? (
           {getPropertyNames('source').length > 0 ? (
@@ -306,20 +305,20 @@ class MainDetails extends React.Component<Props, State> {
           <Row>
           <Row>
             <Field>
             <Field>
               <Label>Id</Label>
               <Label>Id</Label>
-              {this.renderValue(this.props.item ? this.props.item.id || '-' : '-', 'id')}
+              {this.renderValue(this.props.item ? this.props.item.id || '-' : '-')}
             </Field>
             </Field>
           </Row>
           </Row>
           <Row>
           <Row>
             <Field>
             <Field>
               <Label>Created</Label>
               <Label>Created</Label>
-              {this.props.item && this.props.item.created_at ? this.renderValue(DateUtils.getLocalTime(this.props.item.created_at).format('YYYY-MM-DD HH:mm:ss'), 'created') : <Value>-</Value>}
+              {this.props.item && this.props.item.created_at ? this.renderValue(DateUtils.getLocalTime(this.props.item.created_at).format('YYYY-MM-DD HH:mm:ss')) : <Value>-</Value>}
             </Field>
             </Field>
           </Row>
           </Row>
           {lastUpdated ? (
           {lastUpdated ? (
             <Row>
             <Row>
               <Field>
               <Field>
                 <Label>Last Updated</Label>
                 <Label>Last Updated</Label>
-                <Value data-test-id="mainDetails-updated">{lastUpdated}</Value>
+                <Value>{lastUpdated}</Value>
               </Field>
               </Field>
             </Row>
             </Row>
           ) : null}
           ) : null}
@@ -357,7 +356,6 @@ class MainDetails extends React.Component<Props, State> {
           <Row>
           <Row>
             <EndpointLogos
             <EndpointLogos
               endpoint={(destinationEndpoint ? destinationEndpoint.type : '') as any}
               endpoint={(destinationEndpoint ? destinationEndpoint.type : '') as any}
-              data-test-id="mainDetails-targetLogo"
             />
             />
           </Row>
           </Row>
           {getPropertyNames('destination').length > 0 ? (
           {getPropertyNames('destination').length > 0 ? (
@@ -403,7 +401,7 @@ class MainDetails extends React.Component<Props, State> {
 
 
     return (
     return (
       <Loading>
       <Loading>
-        <StatusImage loading data-test-id="mainDetails-loading" />
+        <StatusImage loading />
       </Loading>
       </Loading>
     )
     )
   }
   }

+ 0 - 1
src/components/modules/TransferModule/MigrationDetailsContent/MigrationDetailsContent.tsx

@@ -106,7 +106,6 @@ class MigrationDetailsContent extends React.Component<Props> {
         endpoints={this.props.endpoints}
         endpoints={this.props.endpoints}
         bottomControls={this.renderBottomControls()}
         bottomControls={this.renderBottomControls()}
         loading={this.props.detailsLoading}
         loading={this.props.detailsLoading}
-        data-test-id="mdContent-mainDetails"
       />
       />
     )
     )
   }
   }

+ 0 - 3
src/components/modules/TransferModule/ReplicaDetailsContent/ReplicaDetailsContent.tsx

@@ -147,7 +147,6 @@ class ReplicaDetailsContent extends React.Component<Props, State> {
             primary
             primary
             disabled={this.isEndpointMissing()}
             disabled={this.isEndpointMissing()}
             onClick={this.props.onCreateMigrationClick}
             onClick={this.props.onCreateMigrationClick}
-            data-test-id="rdContent-createButton"
           >Create Migration
           >Create Migration
           </Button>
           </Button>
         </ButtonColumn>
         </ButtonColumn>
@@ -156,7 +155,6 @@ class ReplicaDetailsContent extends React.Component<Props, State> {
             alert
             alert
             hollow
             hollow
             onClick={this.props.onDeleteReplicaClick}
             onClick={this.props.onDeleteReplicaClick}
-            data-test-id="rdContent-deleteButton"
           >Delete Replica
           >Delete Replica
           </Button>
           </Button>
         </ButtonColumn>
         </ButtonColumn>
@@ -184,7 +182,6 @@ class ReplicaDetailsContent extends React.Component<Props, State> {
         endpoints={this.props.endpoints}
         endpoints={this.props.endpoints}
         networks={this.props.networks}
         networks={this.props.networks}
         bottomControls={this.renderBottomControls()}
         bottomControls={this.renderBottomControls()}
-        data-test-id="rdContent-mainDetails"
       />
       />
     )
     )
   }
   }

+ 2 - 3
src/components/modules/TransferModule/ReplicaExecutionOptions/ReplicaExecutionOptions.tsx

@@ -117,13 +117,12 @@ class ReplicaExecutionOptions extends React.Component<Props, State> {
               value={this.getFieldValue(field)}
               value={this.getFieldValue(field)}
               label={LabelDictionary.get(field.name)}
               label={LabelDictionary.get(field.name)}
               onChange={value => this.handleValueChange(field, value)}
               onChange={value => this.handleValueChange(field, value)}
-              data-test-id={`reOptions-option-${field.name}`}
             />
             />
           ))}
           ))}
         </Form>
         </Form>
         <Buttons>
         <Buttons>
-          <Button secondary onClick={this.props.onCancelClick} data-test-id="reOptions-cancelButton">Cancel</Button>
-          <Button onClick={() => { this.props.onExecuteClick(this.state.fields) }} data-test-id="reOptions-execButton">{this.props.executionLabel}</Button>
+          <Button secondary onClick={this.props.onCancelClick}>Cancel</Button>
+          <Button onClick={() => { this.props.onExecuteClick(this.state.fields) }}>{this.props.executionLabel}</Button>
         </Buttons>
         </Buttons>
       </Wrapper>
       </Wrapper>
     )
     )

+ 2 - 2
src/components/modules/TransferModule/ReplicaMigrationOptions/ReplicaMigrationOptions.tsx

@@ -294,8 +294,8 @@ class ReplicaMigrationOptions extends React.Component<Props, State> {
         <Image />
         <Image />
         {this.renderBody()}
         {this.renderBody()}
         <Buttons>
         <Buttons>
-          <Button secondary onClick={this.props.onCancelClick} data-test-id="rmOptions-cancelButton">Cancel</Button>
-          <Button onClick={() => { this.migrate() }} data-test-id="rmOptions-execButton">Migrate</Button>
+          <Button secondary onClick={this.props.onCancelClick}>Cancel</Button>
+          <Button onClick={() => { this.migrate() }}>Migrate</Button>
         </Buttons>
         </Buttons>
       </Wrapper>
       </Wrapper>
     )
     )

+ 1 - 2
src/components/modules/TransferModule/Schedule/Schedule.tsx

@@ -206,7 +206,7 @@ class Schedule extends React.Component<Props, State> {
 
 
     return (
     return (
       <LoadingWrapper>
       <LoadingWrapper>
-        <StatusImage loading data-test-id="schedule-loadingStatus" />
+        <StatusImage loading />
         <LoadingText>Loading schedules...</LoadingText>
         <LoadingText>Loading schedules...</LoadingText>
       </LoadingWrapper>
       </LoadingWrapper>
     )
     )
@@ -316,7 +316,6 @@ class Schedule extends React.Component<Props, State> {
         <Timezone>
         <Timezone>
           <TimezoneLabel>Show all times in</TimezoneLabel>
           <TimezoneLabel>Show all times in</TimezoneLabel>
           <DropdownLink
           <DropdownLink
-            data-test-id="schedule-timezoneDropdown"
             items={timezoneItems}
             items={timezoneItems}
             selectedItem={selectedItem}
             selectedItem={selectedItem}
             onChange={item => { this.props.onTimezoneChange(item.value === 'utc' ? 'utc' : 'local') }}
             onChange={item => { this.props.onTimezoneChange(item.value === 'utc' ? 'utc' : 'local') }}

+ 1 - 10
src/components/modules/TransferModule/ScheduleItem/ScheduleItem.tsx

@@ -230,7 +230,6 @@ class ScheduleItem extends React.Component<Props> {
         useBold={this.shouldUseBold('month')}
         useBold={this.shouldUseBold('month')}
         selectedItem={this.getFieldValue(items, 'month')}
         selectedItem={this.getFieldValue(items, 'month')}
         onChange={item => { this.handleMonthChange(item) }}
         onChange={item => { this.handleMonthChange(item) }}
-        data-test-id="scheduleItem-monthDropdown"
       />
       />
     )
     )
   }
   }
@@ -255,7 +254,6 @@ class ScheduleItem extends React.Component<Props> {
         useBold={this.shouldUseBold('dom')}
         useBold={this.shouldUseBold('dom')}
         selectedItem={this.getFieldValue(items, 'dom')}
         selectedItem={this.getFieldValue(items, 'dom')}
         onChange={item => { this.props.onChange({ schedule: { dom: item.value } }) }}
         onChange={item => { this.props.onChange({ schedule: { dom: item.value } }) }}
-        data-test-id="scheduleItem-dayOfMonthDropdown"
       />
       />
     )
     )
   }
   }
@@ -280,7 +278,6 @@ class ScheduleItem extends React.Component<Props> {
         useBold={this.shouldUseBold('dow')}
         useBold={this.shouldUseBold('dow')}
         selectedItem={this.getFieldValue(items, 'dow', true)}
         selectedItem={this.getFieldValue(items, 'dow', true)}
         onChange={item => { this.props.onChange({ schedule: { dow: item.value } }) }}
         onChange={item => { this.props.onChange({ schedule: { dow: item.value } }) }}
-        data-test-id="scheduleItem-dayOfWeekDropdown"
       />
       />
     )
     )
   }
   }
@@ -303,7 +300,6 @@ class ScheduleItem extends React.Component<Props> {
         useBold={this.shouldUseBold('hour')}
         useBold={this.shouldUseBold('hour')}
         selectedItem={this.getFieldValue(items, 'hour', true, 1)}
         selectedItem={this.getFieldValue(items, 'hour', true, 1)}
         onChange={item => { this.handleHourChange(item.value) }}
         onChange={item => { this.handleHourChange(item.value) }}
-        data-test-id="scheduleItem-hourDropdown"
       />
       />
     )
     )
   }
   }
@@ -326,7 +322,6 @@ class ScheduleItem extends React.Component<Props> {
         useBold={this.shouldUseBold('minute')}
         useBold={this.shouldUseBold('minute')}
         selectedItem={this.getFieldValue(items, 'minute', true, 1)}
         selectedItem={this.getFieldValue(items, 'minute', true, 1)}
         onChange={item => { this.props.onChange({ schedule: { minute: item.value } }) }}
         onChange={item => { this.props.onChange({ schedule: { minute: item.value } }) }}
-        data-test-id="scheduleItem-minuteDropdown"
       />
       />
     )
     )
   }
   }
@@ -356,7 +351,7 @@ class ScheduleItem extends React.Component<Props> {
   render() {
   render() {
     const enabled = typeof this.props.item.enabled !== 'undefined' && this.props.item.enabled !== null ? this.props.item.enabled : false
     const enabled = typeof this.props.item.enabled !== 'undefined' && this.props.item.enabled !== null ? this.props.item.enabled : false
     return (
     return (
-      <Wrapper data-test-id="scheduleItem">
+      <Wrapper>
         <Data width={this.props.colWidths[0]}>
         <Data width={this.props.colWidths[0]}>
           {this.props.enabling ? (
           {this.props.enabling ? (
             <EnablingIcon>
             <EnablingIcon>
@@ -369,7 +364,6 @@ class ScheduleItem extends React.Component<Props> {
               disabled={this.props.deleting}
               disabled={this.props.deleting}
               checked={enabled}
               checked={enabled}
               onChange={itemEnabled => { this.props.onChange({ enabled: itemEnabled }, true) }}
               onChange={itemEnabled => { this.props.onChange({ enabled: itemEnabled }, true) }}
-              data-test-id="scheduleItem-enabled"
             />
             />
           )}
           )}
         </Data>
         </Data>
@@ -402,7 +396,6 @@ class ScheduleItem extends React.Component<Props> {
               letterSpacing: '1px',
               letterSpacing: '1px',
               padding: '0 0 1px 3px',
               padding: '0 0 1px 3px',
             }}
             }}
-            data-test-id="scheduleItem-optionsButton"
           >•••
           >•••
           </Button>
           </Button>
         </Data>
         </Data>
@@ -412,7 +405,6 @@ class ScheduleItem extends React.Component<Props> {
           </DeletingIcon>
           </DeletingIcon>
         ) : (
         ) : (
           <DeleteButton
           <DeleteButton
-            data-test-id="scheduleItem-deleteButton"
             onClick={this.props.onDeleteClick}
             onClick={this.props.onDeleteClick}
             hidden={this.props.item.enabled}
             hidden={this.props.item.enabled}
           />
           />
@@ -423,7 +415,6 @@ class ScheduleItem extends React.Component<Props> {
           </SavingIcon>
           </SavingIcon>
         ) : (
         ) : (
           <SaveButton
           <SaveButton
-            data-test-id="scheduleItem-saveButton"
             onClick={this.props.onSaveSchedule}
             onClick={this.props.onSaveSchedule}
             hidden={this.props.item.enabled
             hidden={this.props.item.enabled
           || !this.props.unsavedSchedules.find(us => us.id === this.props.item.id)}
           || !this.props.unsavedSchedules.find(us => us.id === this.props.item.id)}

+ 1 - 1
src/components/modules/TransferModule/TaskItem/TaskItem.tsx

@@ -271,7 +271,7 @@ class TaskItem extends React.Component<Props> {
               <ProgressUpdateDate width={this.props.columnWidths[0]}>
               <ProgressUpdateDate width={this.props.columnWidths[0]}>
                 <span>{DateUtils.getLocalTime(update.created_at).format('YYYY-MM-DD HH:mm:ss')}</span>
                 <span>{DateUtils.getLocalTime(update.created_at).format('YYYY-MM-DD HH:mm:ss')}</span>
               </ProgressUpdateDate>
               </ProgressUpdateDate>
-              <ProgressUpdateValue data-test-id={`taskItem-progressUpdateMessage-${i}`}>
+              <ProgressUpdateValue>
                 {update.message}
                 {update.message}
                 {progressPercentage && (
                 {progressPercentage && (
                   <ProgressBar
                   <ProgressBar

+ 0 - 1
src/components/modules/TransferModule/Tasks/Tasks.tsx

@@ -158,7 +158,6 @@ class Tasks extends React.Component<Props, State> {
             columnWidths={ColumnWidths}
             columnWidths={ColumnWidths}
             open={Boolean(this.state.openedItems.find(i => i.id === item.id))}
             open={Boolean(this.state.openedItems.find(i => i.id === item.id))}
             onDependsOnClick={id => { this.handleDependsOnClick(id) }}
             onDependsOnClick={id => { this.handleDependsOnClick(id) }}
-            data-test-id={`tasks-item-${item.id}`}
           />
           />
         ))}
         ))}
       </Body>
       </Body>

+ 1 - 4
src/components/modules/TransferModule/Timeline/Timeline.tsx

@@ -166,10 +166,9 @@ class Timeline extends React.Component<Props> {
               key={item.id}
               key={item.id}
               ref={(ref: HTMLElement | null | undefined) => { this.itemRef = ref }}
               ref={(ref: HTMLElement | null | undefined) => { this.itemRef = ref }}
               onClick={() => { if (this.props.onItemClick) this.props.onItemClick(item) }}
               onClick={() => { if (this.props.onItemClick) this.props.onItemClick(item) }}
-              data-test-id={`timeline-item-${item.id}`}
             >
             >
               <StatusIcon status={item.status} useBackground />
               <StatusIcon status={item.status} useBackground />
-              <ItemLabel selected={this.props.selectedItem && this.props.selectedItem.id === item.id} data-test-id={`timeline-label-${item.id}`}>
+              <ItemLabel selected={this.props.selectedItem && this.props.selectedItem.id === item.id}>
                 {DateUtils.getLocalTime(item.created_at).format('DD MMM YYYY')}
                 {DateUtils.getLocalTime(item.created_at).format('DD MMM YYYY')}
               </ItemLabel>
               </ItemLabel>
             </Item>
             </Item>
@@ -187,7 +186,6 @@ class Timeline extends React.Component<Props> {
           forceShow={!this.props.items || !this.props.items.length}
           forceShow={!this.props.items || !this.props.items.length}
           primary={Boolean(this.props.items && this.props.items.length)}
           primary={Boolean(this.props.items && this.props.items.length)}
           onClick={this.props.onPreviousClick}
           onClick={this.props.onPreviousClick}
-          data-test-id="timeline-previous"
         />
         />
         {this.renderMainLine()}
         {this.renderMainLine()}
         {this.renderItems()}
         {this.renderItems()}
@@ -195,7 +193,6 @@ class Timeline extends React.Component<Props> {
           orientation="right"
           orientation="right"
           forceShow={!this.props.items || !this.props.items.length}
           forceShow={!this.props.items || !this.props.items.length}
           onClick={this.props.onNextClick}
           onClick={this.props.onNextClick}
-          data-test-id="timeline-next"
         />
         />
       </Wrapper>
       </Wrapper>
     )
     )

+ 2 - 2
src/components/modules/TransferModule/TransferDetailsTable/TransferDetailsTable.tsx

@@ -208,11 +208,11 @@ class TransferDetailsTable extends React.Component<Props, State> {
         <RowHeader>
         <RowHeader>
           <RowHeaderColumn>
           <RowHeaderColumn>
             <HeaderIcon icon={icon} />
             <HeaderIcon icon={icon} />
-            <HeaderName source data-test-id={`${TEST_ID}-source-${icon}`}>{sourceName}</HeaderName>
+            <HeaderName source>{sourceName}</HeaderName>
             {destinationName ? <ArrowIcon /> : null}
             {destinationName ? <ArrowIcon /> : null}
           </RowHeaderColumn>
           </RowHeaderColumn>
           <RowHeaderColumn>
           <RowHeaderColumn>
-            <HeaderName data-test-id={`${TEST_ID}-destination-${icon}`}>{destinationName}</HeaderName>
+            <HeaderName>{destinationName}</HeaderName>
           </RowHeaderColumn>
           </RowHeaderColumn>
         </RowHeader>
         </RowHeader>
         <Collapse isOpened={isOpened}>
         <Collapse isOpened={isOpened}>

+ 1 - 2
src/components/modules/TransferModule/TransferItemModal/TransferItemModal.tsx

@@ -34,7 +34,6 @@ import WizardStorage from '@src/components/modules/WizardModule/WizardStorage'
 import type {
 import type {
   UpdateData, TransferItemDetails, MigrationItemDetails,
   UpdateData, TransferItemDetails, MigrationItemDetails,
 } from '@src/@types/MainItem'
 } from '@src/@types/MainItem'
-import type { NavigationItem } from '@src/components/ui/Panel'
 import {
 import {
   Endpoint, EndpointUtils, StorageBackend, StorageMap,
   Endpoint, EndpointUtils, StorageBackend, StorageMap,
 } from '@src/@types/Endpoint'
 } from '@src/@types/Endpoint'
@@ -787,7 +786,7 @@ class TransferItemModal extends React.Component<Props, State> {
   }
   }
 
 
   render() {
   render() {
-    const navigationItems: NavigationItem[] = [
+    const navigationItems: Panel['props']['navigationItems'] = [
       {
       {
         value: 'source_options',
         value: 'source_options',
         label: 'Source Options',
         label: 'Source Options',

+ 4 - 4
src/components/ui/Lists/MainListItem/MainListItem.tsx → src/components/modules/TransferModule/TransferListItem/TransferListItem.tsx

@@ -117,7 +117,7 @@ type Props = {
   onSelectedChange: (value: boolean) => void,
   onSelectedChange: (value: boolean) => void,
 }
 }
 @observer
 @observer
-class MainListItem extends React.Component<Props> {
+class TransferListItem extends React.Component<Props> {
   getStatus() {
   getStatus() {
     return this.props.item.last_execution_status
     return this.props.item.last_execution_status
   }
   }
@@ -171,9 +171,9 @@ class MainListItem extends React.Component<Props> {
     const destinationType = this.props.endpointType(this.props.item.destination_endpoint_id)
     const destinationType = this.props.endpointType(this.props.item.destination_endpoint_id)
     const endpointImages = (
     const endpointImages = (
       <EndpointsImages>
       <EndpointsImages>
-        <EndpointLogos data-test-id="mainListItem-sourceLogo" height={32} endpoint={sourceType as any} />
+        <EndpointLogos height={32} endpoint={sourceType as any} />
         <EndpointImageArrow />
         <EndpointImageArrow />
-        <EndpointLogos data-test-id="mainListItem-destLogo" height={32} endpoint={destinationType as any} />
+        <EndpointLogos height={32} endpoint={destinationType as any} />
       </EndpointsImages>
       </EndpointsImages>
     )
     )
     const status = this.getStatus()
     const status = this.getStatus()
@@ -212,4 +212,4 @@ class MainListItem extends React.Component<Props> {
   }
   }
 }
 }
 
 
-export default MainListItem
+export default TransferListItem

+ 0 - 0
src/components/ui/Lists/MainListItem/images/arrow.svg → src/components/modules/TransferModule/TransferListItem/images/arrow.svg


+ 0 - 0
src/components/ui/Lists/MainListItem/images/schedule.svg → src/components/modules/TransferModule/TransferListItem/images/schedule.svg


+ 6 - 0
src/components/modules/TransferModule/TransferListItem/package.json

@@ -0,0 +1,6 @@
+{
+  "name": "TransferListItem",
+  "version": "0.0.0",
+  "private": true,
+  "main": "./TransferListItem.tsx"
+}

+ 3 - 3
src/components/ui/Lists/MainListItem/story.tsx → src/components/modules/TransferModule/TransferListItem/story.tsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 import React from 'react'
 import React from 'react'
 import { storiesOf } from '@storybook/react'
 import { storiesOf } from '@storybook/react'
-import MainListItem from '.'
+import TransferListItem from './TransferListItem'
 
 
 const item: any = {
 const item: any = {
   origin_endpoint_id: 'openstack',
   origin_endpoint_id: 'openstack',
@@ -32,7 +32,7 @@ const endpointType = (id: any) => id
 
 
 storiesOf('MainListItem', module)
 storiesOf('MainListItem', module)
   .add('completed', () => (
   .add('completed', () => (
-    <MainListItem
+    <TransferListItem
       item={item}
       item={item}
       endpointType={endpointType}
       endpointType={endpointType}
       selected={false}
       selected={false}
@@ -44,7 +44,7 @@ storiesOf('MainListItem', module)
     />
     />
   ))
   ))
   .add('running', () => (
   .add('running', () => (
-    <MainListItem
+    <TransferListItem
       item={item2}
       item={item2}
       endpointType={endpointType}
       endpointType={endpointType}
       selected={false}
       selected={false}

+ 0 - 0
src/components/ui/Lists/MainListItem/test.tsx → src/components/modules/TransferModule/TransferListItem/test.tsx


+ 6 - 9
src/components/modules/UserModule/UserDetailsContent/UserDetailsContent.tsx

@@ -112,7 +112,6 @@ class UserDetailsContent extends React.Component<Props> {
           <Button
           <Button
             hollow
             hollow
             onClick={this.props.onUpdatePasswordClick}
             onClick={this.props.onUpdatePasswordClick}
-            data-test-id={`${TEST_ID}-updateButton`}
           >Change password
           >Change password
           </Button>
           </Button>
         </ButtonsColumn>
         </ButtonsColumn>
@@ -122,7 +121,6 @@ class UserDetailsContent extends React.Component<Props> {
             hollow
             hollow
             onClick={() => { this.props.onDeleteClick() }}
             onClick={() => { this.props.onDeleteClick() }}
             disabled={this.props.isLoggedUser}
             disabled={this.props.isLoggedUser}
-            data-test-id={`${TEST_ID}-deleteUserButton`}
           >Delete user
           >Delete user
           </Button>
           </Button>
         </ButtonsColumn>
         </ButtonsColumn>
@@ -163,7 +161,7 @@ class UserDetailsContent extends React.Component<Props> {
       <Info>
       <Info>
         <Field>
         <Field>
           <Label>Name</Label>
           <Label>Name</Label>
-          {this.renderValue(user.name, 'name')}
+          {this.renderValue(user.name)}
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>Description</Label>
           <Label>Description</Label>
@@ -171,15 +169,15 @@ class UserDetailsContent extends React.Component<Props> {
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>ID</Label>
           <Label>ID</Label>
-          {this.renderValue(user.id, 'id')}
+          {this.renderValue(user.id)}
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>Email</Label>
           <Label>Email</Label>
-          {this.renderValue(user.email || '-', 'email')}
+          {this.renderValue(user.email || '-')}
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>Primary Project</Label>
           <Label>Primary Project</Label>
-          {this.renderValue(primaryProjectName || '-', 'primaryProject')}
+          {this.renderValue(primaryProjectName || '-')}
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>Project Membership</Label>
           <Label>Project Membership</Label>
@@ -187,16 +185,15 @@ class UserDetailsContent extends React.Component<Props> {
         </Field>
         </Field>
         <Field>
         <Field>
           <Label>Enabled</Label>
           <Label>Enabled</Label>
-          <Value data-test-id={`${TEST_ID}-enabled`}>{user.enabled ? 'Yes' : 'No'}</Value>
+          <Value>{user.enabled ? 'Yes' : 'No'}</Value>
         </Field>
         </Field>
       </Info>
       </Info>
     )
     )
   }
   }
 
 
-  renderValue(value: string, dataTestId?: string) {
+  renderValue(value: string) {
     return value !== '-' ? (
     return value !== '-' ? (
       <CopyValue
       <CopyValue
-        data-test-id={`${TEST_ID}-${dataTestId || ''}`}
         value={value}
         value={value}
         maxWidth="90%"
         maxWidth="90%"
       />
       />

+ 6 - 7
src/components/modules/UserModule/UserListItem/UserListItem.tsx

@@ -93,34 +93,33 @@ type Props = {
   onClick: () => void,
   onClick: () => void,
   getProjectName: (projectId: string | null | undefined) => string,
   getProjectName: (projectId: string | null | undefined) => string,
 }
 }
-const testName = 'ulItem'
 @observer
 @observer
 class UserListItem extends React.Component<Props> {
 class UserListItem extends React.Component<Props> {
   render() {
   render() {
     return (
     return (
       <Wrapper>
       <Wrapper>
-        <Content data-test-id={`${testName}-content`} onClick={this.props.onClick}>
+        <Content onClick={this.props.onClick}>
           <Image />
           <Image />
           <Title>
           <Title>
-            <TitleLabel data-test-id={`${testName}-name`}>{this.props.item.name}</TitleLabel>
-            <Subtitle data-test-id={`${testName}-description`}>{this.props.item.description}</Subtitle>
+            <TitleLabel>{this.props.item.name}</TitleLabel>
+            <Subtitle>{this.props.item.description}</Subtitle>
           </Title>
           </Title>
           <Body>
           <Body>
             <Data percentage={45}>
             <Data percentage={45}>
               <ItemLabel>Email</ItemLabel>
               <ItemLabel>Email</ItemLabel>
-              <ItemValue data-test-id={`${testName}-email`}>
+              <ItemValue>
                 {this.props.item.email || '-'}
                 {this.props.item.email || '-'}
               </ItemValue>
               </ItemValue>
             </Data>
             </Data>
             <Data percentage={35}>
             <Data percentage={35}>
               <ItemLabel>Primary Project</ItemLabel>
               <ItemLabel>Primary Project</ItemLabel>
-              <ItemValue data-test-id={`${testName}-project`}>
+              <ItemValue>
                 {this.props.getProjectName(this.props.item.project_id)}
                 {this.props.getProjectName(this.props.item.project_id)}
               </ItemValue>
               </ItemValue>
             </Data>
             </Data>
             <Data percentage={20}>
             <Data percentage={20}>
               <ItemLabel>Enabled</ItemLabel>
               <ItemLabel>Enabled</ItemLabel>
-              <ItemValue data-test-id={`${testName}-enabled`}>
+              <ItemValue>
                 {this.props.item.enabled ? 'Yes' : 'No'}
                 {this.props.item.enabled ? 'Yes' : 'No'}
               </ItemValue>
               </ItemValue>
             </Data>
             </Data>

+ 0 - 3
src/components/modules/UserModule/UserModal/UserModal.tsx

@@ -81,7 +81,6 @@ type State = {
   confirmPassword: string,
   confirmPassword: string,
   description?: string,
   description?: string,
 }
 }
-const testName = 'userModal'
 @observer
 @observer
 class UserModal extends React.Component<Props, State> {
 class UserModal extends React.Component<Props, State> {
   UNSAFE_componentWillMount() {
   UNSAFE_componentWillMount() {
@@ -176,7 +175,6 @@ class UserModal extends React.Component<Props, State> {
     return (
     return (
       <FieldInput
       <FieldInput
         layout="modal"
         layout="modal"
-        data-test-id={`${testName}-field-${field.name}`}
         key={field.name}
         key={field.name}
         name={field.name}
         name={field.name}
         label={LabelDictionary.get(field.name)}
         label={LabelDictionary.get(field.name)}
@@ -275,7 +273,6 @@ class UserModal extends React.Component<Props, State> {
             >Cancel
             >Cancel
             </Button>
             </Button>
             <Button
             <Button
-              data-test-id={`${testName}-updateButton`}
               large
               large
               disabled={this.props.loading}
               disabled={this.props.loading}
               onClick={() => { this.handleUpdateClick() }}
               onClick={() => { this.handleUpdateClick() }}

+ 1 - 1
src/components/modules/WizardModule/WizardBreadcrumbs/WizardBreadcrumbs.tsx

@@ -50,7 +50,7 @@ class WizardBreadcrumbs extends React.Component<Props> {
       <Wrapper>
       <Wrapper>
         {this.props.pages.map(page => (
         {this.props.pages.map(page => (
           <Breadcrumb key={page.id}>
           <Breadcrumb key={page.id}>
-            <Name selected={this.props.selected.id === page.id} data-test-id={`wBreadCrumbs-name-${page.id}`}>{page.breadcrumb}</Name>
+            <Name selected={this.props.selected.id === page.id}>{page.breadcrumb}</Name>
             <ArrowStyled primary={this.props.selected.id === page.id} useDefaultCursor />
             <ArrowStyled primary={this.props.selected.id === page.id} useDefaultCursor />
           </Breadcrumb>
           </Breadcrumb>
         ))}
         ))}

+ 0 - 3
src/components/modules/WizardModule/WizardEndpointList/WizardEndpointList.tsx

@@ -97,7 +97,6 @@ class WizardEndpointList extends React.Component<Props> {
 
 
       actionInput = (
       actionInput = (
         <Dropdown
         <Dropdown
-          data-test-id={`wEndpointList-dropdown-${provider}`}
           primary={Boolean(selectedItem)}
           primary={Boolean(selectedItem)}
           items={items}
           items={items}
           valueField="id"
           valueField="id"
@@ -121,7 +120,6 @@ class WizardEndpointList extends React.Component<Props> {
           hollow
           hollow
           hoverPrimary
           hoverPrimary
           onClick={() => { this.props.onAddEndpoint(provider) }}
           onClick={() => { this.props.onAddEndpoint(provider) }}
-          data-test-id={`wEndpointList-addButton-${provider}`}
         >Add
         >Add
         </Button>
         </Button>
       )
       )
@@ -133,7 +131,6 @@ class WizardEndpointList extends React.Component<Props> {
           height={128}
           height={128}
           endpoint={provider}
           endpoint={provider}
           disabled={items.length === 0}
           disabled={items.length === 0}
-          data-test-id={`wEndpointList-logo-${provider}`}
         />
         />
         {actionInput}
         {actionInput}
       </Item>
       </Item>

+ 4 - 7
src/components/modules/WizardModule/WizardInstances/WizardInstances.tsx

@@ -264,7 +264,7 @@ class WizardInstances extends React.Component<Props, State> {
     return (
     return (
       <SearchNotFound>
       <SearchNotFound>
         <StatusImage status="ERROR" />
         <StatusImage status="ERROR" />
-        <SearchNotFoundText data-test-id="wInstances-notFoundText">Your search returned no results</SearchNotFoundText>
+        <SearchNotFoundText>Your search returned no results</SearchNotFoundText>
         {subtitle}
         {subtitle}
         <Button hollow onClick={() => { this.props.onReloadClick() }}>Retry</Button>
         <Button hollow onClick={() => { this.props.onReloadClick() }}>Retry</Button>
       </SearchNotFound>
       </SearchNotFound>
@@ -290,7 +290,7 @@ class WizardInstances extends React.Component<Props, State> {
 
 
     return (
     return (
       <LoadingWrapper>
       <LoadingWrapper>
-        <StatusImage loading data-test-id="wInstances-loadingStatus" />
+        <StatusImage loading />
         <LoadingText>Loading instances...</LoadingText>
         <LoadingText>Loading instances...</LoadingText>
       </LoadingWrapper>
       </LoadingWrapper>
     )
     )
@@ -320,7 +320,6 @@ class WizardInstances extends React.Component<Props, State> {
                 if (!this.isCheckboxMouseDown) this.props.onInstanceClick(instance)
                 if (!this.isCheckboxMouseDown) this.props.onInstanceClick(instance)
               }}
               }}
               selected={selected}
               selected={selected}
-              data-test-id={`wInstances-item-${instance.id}`}
             >
             >
               <CheckboxStyled
               <CheckboxStyled
                 checked={selected}
                 checked={selected}
@@ -328,7 +327,7 @@ class WizardInstances extends React.Component<Props, State> {
                 onMouseDown={() => { this.isCheckboxMouseDown = true }}
                 onMouseDown={() => { this.isCheckboxMouseDown = true }}
                 onMouseUp={() => { this.isCheckboxMouseDown = false }}
                 onMouseUp={() => { this.isCheckboxMouseDown = false }}
               />
               />
-              <InstanceContent data-test-id="wInstances-instanceItem">
+              <InstanceContent>
                 <Image />
                 <Image />
                 <Label>
                 <Label>
                   <LabelTitle>{instance.name}</LabelTitle>
                   <LabelTitle>{instance.name}</LabelTitle>
@@ -362,7 +361,6 @@ class WizardInstances extends React.Component<Props, State> {
             value={this.state.searchText}
             value={this.state.searchText}
             loading={this.props.searching}
             loading={this.props.searching}
             placeholder="Search VMs"
             placeholder="Search VMs"
-            data-test-id="wInstances-searchInput"
           />
           />
           {this.props.hasSourceOptions ? (
           {this.props.hasSourceOptions ? (
             <InfoIcon
             <InfoIcon
@@ -374,11 +372,10 @@ class WizardInstances extends React.Component<Props, State> {
           ) : null}
           ) : null}
         </SearchInputInfo>
         </SearchInputInfo>
         <FilterInfo>
         <FilterInfo>
-          <SelectionInfo data-test-id="wInstances-selInfo">{count} instance{plural} selected</SelectionInfo>
+          <SelectionInfo>{count} instance{plural} selected</SelectionInfo>
           <FilterSeparator>|</FilterSeparator>
           <FilterSeparator>|</FilterSeparator>
           <ReloadButton
           <ReloadButton
             onClick={() => { this.props.onReloadClick() }}
             onClick={() => { this.props.onReloadClick() }}
-            data-test-id="wInstances-reloadButton"
           />
           />
         </FilterInfo>
         </FilterInfo>
       </FiltersWrapper>
       </FiltersWrapper>

+ 2 - 2
src/components/modules/WizardModule/WizardNetworks/WizardNetworks.tsx

@@ -149,7 +149,7 @@ class WizardNetworks extends React.Component<Props> {
     return (
     return (
       <NoNicsMessage>
       <NoNicsMessage>
         <BigNetworkImage />
         <BigNetworkImage />
-        <NoNicsTitle data-test-id="wNetworks-noNics">No networks were found</NoNicsTitle>
+        <NoNicsTitle>No networks were found</NoNicsTitle>
         <NoNicsSubtitle>
         <NoNicsSubtitle>
           We could not find any Networks attached to the selected Instances.
           We could not find any Networks attached to the selected Instances.
           Coriolis will skip this step.
           Coriolis will skip this step.
@@ -286,7 +286,7 @@ class WizardNetworks extends React.Component<Props> {
 
 
           const selectedNetwork = this.props.selectedNetworks?.find(n => n.sourceNic.network_name === nic.network_name)
           const selectedNetwork = this.props.selectedNetworks?.find(n => n.sourceNic.network_name === nic.network_name)
           return (
           return (
-            <Nic key={nic.id} data-test-id="networkItem">
+            <Nic key={nic.id}>
               <NetworkImage />
               <NetworkImage />
               <NetworkTitle width={this.props.titleWidth || 320}>
               <NetworkTitle width={this.props.titleWidth || 320}>
                 <NetworkName>{nic.network_name}</NetworkName>
                 <NetworkName>{nic.network_name}</NetworkName>

+ 0 - 1
src/components/modules/WizardModule/WizardOptions/WizardOptions.tsx

@@ -358,7 +358,6 @@ class WizardOptions extends React.Component<Props> {
         enum={field.enum}
         enum={field.enum}
         addNullValue
         addNullValue
         required={field.required}
         required={field.required}
-        data-test-id={`wOptions-field-${field.name}`}
         width={this.props.fieldWidth || ThemeProps.inputSizes.wizard.width}
         width={this.props.fieldWidth || ThemeProps.inputSizes.wizard.width}
         nullableBoolean={field.nullableBoolean}
         nullableBoolean={field.nullableBoolean}
         disabled={field.disabled}
         disabled={field.disabled}

+ 0 - 1
src/components/modules/WizardModule/WizardStorage/WizardStorage.tsx

@@ -241,7 +241,6 @@ class WizardStorage extends React.Component<Props> {
           labelField="name"
           labelField="name"
           valueField="id"
           valueField="id"
           onChange={(item: StorageBackend) => { this.props.onChange({ source: disk, target: item, type }) }}
           onChange={(item: StorageBackend) => { this.props.onChange({ source: disk, target: item, type }) }}
-          data-test-id={`${TEST_ID}-${type}-destination`}
         />
         />
       )
       )
   }
   }

+ 7 - 10
src/components/modules/WizardModule/WizardSummary/WizardSummary.tsx

@@ -252,7 +252,7 @@ class WizardSummary extends React.Component<Props> {
         <SectionTitle>Schedule</SectionTitle>
         <SectionTitle>Schedule</SectionTitle>
         <Table>
         <Table>
           {schedules.map(schedule => (
           {schedules.map(schedule => (
-            <Row key={schedule.id} schedule data-test-id={`wSummary-scheduleItem-${schedule.id || 0}`}>
+            <Row key={schedule.id} schedule>
               {this.renderScheduleLabel(schedule)}
               {this.renderScheduleLabel(schedule)}
             </Row>
             </Row>
           ))}
           ))}
@@ -474,10 +474,10 @@ class WizardSummary extends React.Component<Props> {
 
 
             return (
             return (
               <Option key={optionName}>
               <Option key={optionName}>
-                <OptionLabel data-test-id={`wSummary-optionLabel-${optionName}`} title={optionLabel}>
+                <OptionLabel title={optionLabel}>
                   {optionLabel}
                   {optionLabel}
                 </OptionLabel>
                 </OptionLabel>
-                <OptionValue data-test-id={`wSummary-optionValue-${optionName}`} title={optionValue}>
+                <OptionValue title={optionValue}>
                   {optionValue}
                   {optionValue}
                 </OptionValue>
                 </OptionValue>
               </Option>
               </Option>
@@ -554,10 +554,10 @@ class WizardSummary extends React.Component<Props> {
         <Table>
         <Table>
           {data.networks.map(mapping => (
           {data.networks.map(mapping => (
             <Row key={mapping.sourceNic.network_name} direction="row">
             <Row key={mapping.sourceNic.network_name} direction="row">
-              <SourceNetwork data-test-id="wSummary-networkSource">{mapping.sourceNic.network_name}</SourceNetwork>
+              <SourceNetwork>{mapping.sourceNic.network_name}</SourceNetwork>
               <NetworkArrow />
               <NetworkArrow />
               <TargetNetwork>
               <TargetNetwork>
-                <TargetNetworkName data-test-id="wSummary-networkTarget">{mapping.targetNetwork!.name}</TargetNetworkName>
+                <TargetNetworkName>{mapping.targetNetwork!.name}</TargetNetworkName>
                 {mapping.targetSecurityGroups?.length ? (
                 {mapping.targetSecurityGroups?.length ? (
                   <TargetNetworkName>Security Groups: {mapping.targetSecurityGroups.map(s => (typeof s === 'string' ? s : s.name)).join(', ')}</TargetNetworkName>
                   <TargetNetworkName>Security Groups: {mapping.targetSecurityGroups.map(s => (typeof s === 'string' ? s : s.name)).join(', ')}</TargetNetworkName>
                 ) : null}
                 ) : null}
@@ -639,9 +639,8 @@ class WizardSummary extends React.Component<Props> {
                 secondary
                 secondary
                 small
                 small
                 label={configLoader.config.providerNames[data.source!.type]}
                 label={configLoader.config.providerNames[data.source!.type]}
-                data-test-id="wSummary-sourcePill"
               />
               />
-              <OverviewRowLabel data-test-id="wSummary-source">{data.source ? data.source.name : ''}</OverviewRowLabel>
+              <OverviewRowLabel>{data.source ? data.source.name : ''}</OverviewRowLabel>
             </OverviewRowData>
             </OverviewRowData>
           </OverviewRow>
           </OverviewRow>
           <OverviewRow>
           <OverviewRow>
@@ -651,9 +650,8 @@ class WizardSummary extends React.Component<Props> {
                 secondary
                 secondary
                 small
                 small
                 label={configLoader.config.providerNames[data.target!.type]}
                 label={configLoader.config.providerNames[data.target!.type]}
-                data-test-id="wSummary-targetPill"
               />
               />
-              <OverviewRowLabel data-test-id="wSummary-target">{data.target && data.target.name}</OverviewRowLabel>
+              <OverviewRowLabel>{data.target && data.target.name}</OverviewRowLabel>
             </OverviewRowData>
             </OverviewRowData>
           </OverviewRow>
           </OverviewRow>
           <OverviewRow>
           <OverviewRow>
@@ -663,7 +661,6 @@ class WizardSummary extends React.Component<Props> {
                 alert={type === 'Replica'}
                 alert={type === 'Replica'}
                 small
                 small
                 label={this.props.wizardType.toUpperCase()}
                 label={this.props.wizardType.toUpperCase()}
-                data-test-id="wSummary-typePill"
               />
               />
               <OverviewRowLabel>Coriolis {type}</OverviewRowLabel>
               <OverviewRowLabel>Coriolis {type}</OverviewRowLabel>
             </OverviewRowData>
             </OverviewRowData>

+ 0 - 1
src/components/modules/WizardModule/WizardType/WizardType.tsx

@@ -79,7 +79,6 @@ class WizardType extends React.Component<Props> {
               big
               big
               onChange={this.props.onChange}
               onChange={this.props.onChange}
               checked={this.props.selected === 'replica'}
               checked={this.props.selected === 'replica'}
-              data-test-id="wType-switch"
             />
             />
           </Column>
           </Column>
           <Column width="50%">
           <Column width="50%">

+ 1 - 1
src/components/smart/AssessmentsPage/AssessmentsPage.tsx

@@ -18,7 +18,7 @@ import { observer } from 'mobx-react'
 
 
 import FilterList from '@src/components/ui/Lists/FilterList'
 import FilterList from '@src/components/ui/Lists/FilterList'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import DropdownFilterGroup from '@src/components/ui/Dropdowns/DropdownFilterGroup'
 import DropdownFilterGroup from '@src/components/ui/Dropdowns/DropdownFilterGroup'
 import AssessmentListItem from '@src/components/modules/AssessmentModule/AssessmentListItem'
 import AssessmentListItem from '@src/components/modules/AssessmentModule/AssessmentListItem'

+ 1 - 1
src/components/smart/DashboardPage/DashboardPage.tsx

@@ -26,7 +26,7 @@ import notificationStore from '@src/stores/NotificationStore'
 
 
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 import DashboardContent from '@src/components/modules/DashboardModule/DashboardContent'
 import DashboardContent from '@src/components/modules/DashboardModule/DashboardContent'
 
 
 import Utils from '@src/utils/ObjectUtils'
 import Utils from '@src/utils/ObjectUtils'

+ 1 - 1
src/components/smart/EndpointsPage/EndpointsPage.tsx

@@ -19,7 +19,7 @@ import { observer } from 'mobx-react'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import FilterList from '@src/components/ui/Lists/FilterList'
 import FilterList from '@src/components/ui/Lists/FilterList'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 import EndpointListItem from '@src/components/modules/EndpointModule/EndpointListItem'
 import EndpointListItem from '@src/components/modules/EndpointModule/EndpointListItem'
 import AlertModal from '@src/components/ui/AlertModal'
 import AlertModal from '@src/components/ui/AlertModal'
 import Modal from '@src/components/ui/Modal'
 import Modal from '@src/components/ui/Modal'

+ 1 - 1
src/components/smart/LogsPage/LogsPage.tsx

@@ -18,7 +18,7 @@ import { observer } from 'mobx-react'
 
 
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 import TabNavigation from '@src/components/ui/TabNavigation'
 import TabNavigation from '@src/components/ui/TabNavigation'
 
 
 import logStore from '@src/stores/LogStore'
 import logStore from '@src/stores/LogStore'

+ 3 - 3
src/components/smart/MigrationsPage/MigrationsPage.tsx

@@ -19,9 +19,8 @@ import { observer } from 'mobx-react'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import FilterList from '@src/components/ui/Lists/FilterList'
 import FilterList from '@src/components/ui/Lists/FilterList'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 import AlertModal from '@src/components/ui/AlertModal'
 import AlertModal from '@src/components/ui/AlertModal'
-import MainListItem from '@src/components/ui/Lists/MainListItem'
 
 
 import projectStore from '@src/stores/ProjectStore'
 import projectStore from '@src/stores/ProjectStore'
 import migrationStore from '@src/stores/MigrationStore'
 import migrationStore from '@src/stores/MigrationStore'
@@ -33,6 +32,7 @@ import { ThemePalette } from '@src/components/Theme'
 import replicaMigrationFields from '@src/components/modules/TransferModule/ReplicaMigrationOptions/replicaMigrationFields'
 import replicaMigrationFields from '@src/components/modules/TransferModule/ReplicaMigrationOptions/replicaMigrationFields'
 import { MigrationItem } from '@src/@types/MainItem'
 import { MigrationItem } from '@src/@types/MainItem'
 import userStore from '@src/stores/UserStore'
 import userStore from '@src/stores/UserStore'
+import TransferListItem from '@src/components/modules/TransferModule/TransferListItem'
 import migrationLargeImage from './images/migration-large.svg'
 import migrationLargeImage from './images/migration-large.svg'
 import migrationItemImage from './images/migration.svg'
 import migrationItemImage from './images/migration.svg'
 
 
@@ -254,7 +254,7 @@ class MigrationsPage extends React.Component<{ history: any }, State> {
               }}
               }}
               dropdownActions={BulkActions}
               dropdownActions={BulkActions}
               renderItemComponent={options => (
               renderItemComponent={options => (
-                <MainListItem
+                <TransferListItem
                   {...options}
                   {...options}
                   image={migrationItemImage}
                   image={migrationItemImage}
                   endpointType={id => {
                   endpointType={id => {

+ 1 - 1
src/components/smart/MinionPoolsPage/MinionPoolsPage.tsx

@@ -22,7 +22,7 @@ import Modal from '@src/components/ui/Modal'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import FilterList from '@src/components/ui/Lists/FilterList'
 import FilterList from '@src/components/ui/Lists/FilterList'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 
 
 import type { Action as DropdownAction } from '@src/components/ui/Dropdowns/ActionDropdown'
 import type { Action as DropdownAction } from '@src/components/ui/Dropdowns/ActionDropdown'
 
 

+ 0 - 0
src/components/ui/PageHeader/PageHeader.tsx → src/components/smart/PageHeader/PageHeader.tsx


+ 0 - 0
src/components/ui/PageHeader/package.json → src/components/smart/PageHeader/package.json


+ 0 - 0
src/components/ui/PageHeader/story.tsx → src/components/smart/PageHeader/story.tsx


+ 1 - 1
src/components/smart/ProjectsPage/ProjectsPage.tsx

@@ -19,7 +19,7 @@ import { observer } from 'mobx-react'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import FilterList from '@src/components/ui/Lists/FilterList'
 import FilterList from '@src/components/ui/Lists/FilterList'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 import ProjectListItem from '@src/components/modules/ProjectModule/ProjectListItem'
 import ProjectListItem from '@src/components/modules/ProjectModule/ProjectListItem'
 
 
 import type { Project, RoleAssignment } from '@src/@types/Project'
 import type { Project, RoleAssignment } from '@src/@types/Project'

+ 3 - 3
src/components/smart/ReplicasPage/ReplicasPage.tsx

@@ -19,9 +19,8 @@ import { observer } from 'mobx-react'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import FilterList from '@src/components/ui/Lists/FilterList'
 import FilterList from '@src/components/ui/Lists/FilterList'
-import PageHeader from '@src/components/ui/PageHeader'
+import PageHeader from '@src/components/smart/PageHeader'
 import AlertModal from '@src/components/ui/AlertModal'
 import AlertModal from '@src/components/ui/AlertModal'
-import MainListItem from '@src/components/ui/Lists/MainListItem'
 import Modal from '@src/components/ui/Modal'
 import Modal from '@src/components/ui/Modal'
 import ReplicaExecutionOptions from '@src/components/modules/TransferModule/ReplicaExecutionOptions'
 import ReplicaExecutionOptions from '@src/components/modules/TransferModule/ReplicaExecutionOptions'
 import ReplicaMigrationOptions from '@src/components/modules/TransferModule/ReplicaMigrationOptions'
 import ReplicaMigrationOptions from '@src/components/modules/TransferModule/ReplicaMigrationOptions'
@@ -43,6 +42,7 @@ import { ThemePalette } from '@src/components/Theme'
 import configLoader from '@src/utils/Config'
 import configLoader from '@src/utils/Config'
 import { ReplicaItem } from '@src/@types/MainItem'
 import { ReplicaItem } from '@src/@types/MainItem'
 import userStore from '@src/stores/UserStore'
 import userStore from '@src/stores/UserStore'
+import TransferListItem from '@src/components/modules/TransferModule/TransferListItem'
 import replicaLargeImage from './images/replica-large.svg'
 import replicaLargeImage from './images/replica-large.svg'
 import replicaItemImage from './images/replica.svg'
 import replicaItemImage from './images/replica.svg'
 
 
@@ -352,7 +352,7 @@ class ReplicasPage extends React.Component<{ history: any }, State> {
               onSelectedItemsChange={selectedReplicas => { this.setState({ selectedReplicas }) }}
               onSelectedItemsChange={selectedReplicas => { this.setState({ selectedReplicas }) }}
               onPaginatedItemsChange={paginatedReplicas => { this.handlePaginatedItemsChange(paginatedReplicas) }}
               onPaginatedItemsChange={paginatedReplicas => { this.handlePaginatedItemsChange(paginatedReplicas) }}
               renderItemComponent={options => (
               renderItemComponent={options => (
-                <MainListItem
+                <TransferListItem
                   {...options}
                   {...options}
                   image={replicaItemImage}
                   image={replicaItemImage}
                   showScheduleIcon={this.isReplicaScheduled(options.item.id)}
                   showScheduleIcon={this.isReplicaScheduled(options.item.id)}

+ 1 - 1
src/components/smart/UsersPage/UsersPage.tsx

@@ -19,7 +19,6 @@ import { observer } from 'mobx-react'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import MainTemplate from '@src/components/modules/TemplateModule/MainTemplate'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import Navigation from '@src/components/modules/NavigationModule/Navigation'
 import FilterList from '@src/components/ui/Lists/FilterList'
 import FilterList from '@src/components/ui/Lists/FilterList'
-import PageHeader from '@src/components/ui/PageHeader'
 import UserListItem from '@src/components/modules/UserModule/UserListItem'
 import UserListItem from '@src/components/modules/UserModule/UserListItem'
 
 
 import type { User } from '@src/@types/User'
 import type { User } from '@src/@types/User'
@@ -27,6 +26,7 @@ import type { User } from '@src/@types/User'
 import projectStore from '@src/stores/ProjectStore'
 import projectStore from '@src/stores/ProjectStore'
 import userStore from '@src/stores/UserStore'
 import userStore from '@src/stores/UserStore'
 import configLoader from '@src/utils/Config'
 import configLoader from '@src/utils/Config'
+import PageHeader from '@src/components/smart/PageHeader'
 
 
 const Wrapper = styled.div<any>``
 const Wrapper = styled.div<any>``
 
 

+ 71 - 0
src/components/ui/AlertModal/AlertModal.spec.tsx

@@ -0,0 +1,71 @@
+/*
+Copyright (C) 2017  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import StatusImage from '@src/components/ui/StatusComponents/StatusImage'
+import TestUtils from '@tests/TestUtils'
+import AlertModal from './AlertModal'
+
+jest.mock('../StatusComponents/StatusImage/StatusImage', () => jest.fn(() => null))
+
+describe('AlertModal', () => {
+  it('renders confirmation as default with message and extra message', () => {
+    const message = 'message'
+    const extraMessage = 'extra message'
+    const { queryByText } = render((
+      <AlertModal
+        isOpen
+        message={message}
+        extraMessage={extraMessage}
+      />
+    ))
+    expect(TestUtils.select('AlertModal__Message')?.innerHTML).toBe(message)
+    expect(TestUtils.select('AlertModal__ExtraMessage')?.textContent).toBe(extraMessage)
+
+    expect(queryByText('No')).toBeTruthy()
+    expect(queryByText('Yes')).toBeTruthy()
+    expect(queryByText('Dismiss')).toBeNull()
+    expect(StatusImage).toHaveBeenCalledWith({ status: 'confirmation' }, {})
+  })
+
+  it('has correct buttons for errors', () => {
+    const { queryByText } = render((
+      <AlertModal
+        isOpen
+        message="message"
+        extraMessage="extra message"
+        type="error"
+      />
+    ))
+    expect(queryByText('Dismiss')).toBeTruthy()
+    expect(queryByText('No')).toBeNull()
+    expect(queryByText('Yes')).toBeNull()
+  })
+
+  it('renders loading', () => {
+    const { queryByText } = render((
+      <AlertModal
+        isOpen
+        message="message"
+        extraMessage="extra message"
+        type="loading"
+      />
+    ))
+    expect(queryByText('Dismiss')).toBeNull()
+    expect(queryByText('No')).toBeNull()
+    expect(queryByText('Yes')).toBeNull()
+    expect(StatusImage).toHaveBeenCalledWith({ status: 'RUNNING' }, {})
+  })
+})

+ 7 - 7
src/components/ui/AlertModal/AlertModal.tsx

@@ -84,7 +84,7 @@ class AlertModal extends React.Component<Props> {
 
 
     return (
     return (
       <Buttons centered>
       <Buttons centered>
-        <Button secondary onClick={this.props.onRequestClose} data-test-id="aModal-dismissButton">Dismiss</Button>
+        <Button secondary onClick={this.props.onRequestClose}>Dismiss</Button>
       </Buttons>
       </Buttons>
     )
     )
   }
   }
@@ -96,8 +96,8 @@ class AlertModal extends React.Component<Props> {
 
 
     return (
     return (
       <Buttons>
       <Buttons>
-        <Button secondary onClick={this.props.onRequestClose} data-test-id="aModal-noButton">No</Button>
-        <Button onClick={this.props.onConfirmation} data-test-id="aModal-yesButton">Yes</Button>
+        <Button secondary onClick={this.props.onRequestClose}>No</Button>
+        <Button onClick={this.props.onConfirmation}>Yes</Button>
       </Buttons>
       </Buttons>
     )
     )
   }
   }
@@ -108,10 +108,10 @@ class AlertModal extends React.Component<Props> {
     return (
     return (
       // eslint-disable-next-line react/jsx-props-no-spreading
       // eslint-disable-next-line react/jsx-props-no-spreading
       <Modal {...this.props} isOpen={this.props.isOpen || false}>
       <Modal {...this.props} isOpen={this.props.isOpen || false}>
-        <Wrapper data-test-id="alertModal">
-          <StatusImage status={status} data-test-id="aModal-status" />
-          {this.props.message ? <Message data-test-id="aModal-message">{this.props.message}</Message> : null}
-          {this.props.extraMessage ? <ExtraMessage data-test-id="aModal-extraMessage">{this.props.extraMessage}</ExtraMessage> : null}
+        <Wrapper>
+          <StatusImage status={status} />
+          {this.props.message ? <Message>{this.props.message}</Message> : null}
+          {this.props.extraMessage ? <ExtraMessage>{this.props.extraMessage}</ExtraMessage> : null}
           {this.renderConfirmationButtons()}
           {this.renderConfirmationButtons()}
           {this.renderDismissButton()}
           {this.renderDismissButton()}
         </Wrapper>
         </Wrapper>

+ 0 - 56
src/components/ui/AlertModal/test.tsx

@@ -1,56 +0,0 @@
-/*
-Copyright (C) 2017  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { shallow } from 'enzyme'
-import TW from '../../../utils/TestWrapper'
-import AlertModal from '.'
-
-const wrap = props => new TW(shallow(<AlertModal {...props} />), 'aModal')
-
-describe('AlertModal Component', () => {
-  it('renders confirmation as default with message and extra message', () => {
-    let wrapper = wrap({ message: 'alert-message', extraMessage: 'alert-extra' })
-    expect(wrapper.findText('message')).toBe('alert-message')
-    expect(wrapper.findText('extraMessage')).toBe('alert-extra')
-    expect(wrapper.find('status').prop('status')).toBe('confirmation')
-    expect(wrapper.find('noButton').length).toBe(1)
-    expect(wrapper.find('yesButton').length).toBe(1)
-    expect(wrapper.find('dismissButton').length).toBe(0)
-  })
-
-  it('has correct buttons for confirmation', () => {
-    let wrapper = wrap({ message: 'alert-message', extraMessage: 'alert-extra' })
-    expect(wrapper.find('noButton').prop('secondary')).toBe(true)
-    expect(wrapper.find('yesButton').prop('secondary')).toBe(undefined)
-    expect(wrapper.find('noButton').shallow.dive().dive().text()).toBe('No')
-    expect(wrapper.find('yesButton').shallow.dive().dive().text()).toBe('Yes')
-  })
-
-  it('has correct button for error', () => {
-    let wrapper = wrap({ message: 'alert-message', extraMessage: 'alert-extra', type: 'error' })
-    expect(wrapper.find('dismissButton').length).toBe(1)
-  })
-
-  it('renders loading', () => {
-    let wrapper = wrap({ message: 'alert-message', extraMessage: 'alert-extra', type: 'loading' })
-    expect(wrapper.find('status').prop('status')).toBe('RUNNING')
-    expect(wrapper.find('noButton').length).toBe(0)
-    expect(wrapper.find('yesButton').length).toBe(0)
-    expect(wrapper.find('dismissButton').length).toBe(0)
-  })
-})
-
-
-

+ 46 - 0
src/components/ui/Arrow/Arrow.spec.tsx

@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import { ThemePalette } from '@src/components/Theme'
+import Arrow from './Arrow'
+
+describe('Arrow', () => {
+  it.each`
+    orientation
+    ${'up'}
+    ${'down'}
+    ${'left'}
+    ${'right'}
+  `('renders the $orientation orientation', ({ orientation }) => {
+    render(<Arrow orientation={orientation} />)
+    expect(TestUtils.select('Arrow__Wrapper')?.getAttribute('orientation')).toBe(orientation)
+  })
+
+  it('renderes with primary colors', () => {
+    const { rerender } = render(<Arrow primary />)
+    expect(document.querySelector(`g[stroke="${ThemePalette.primary}"]`)).toBeTruthy()
+    rerender(<Arrow />)
+    expect(document.querySelector(`g[stroke="${ThemePalette.grayscale[4]}"]`)).toBeTruthy()
+  })
+
+  it('renderes with primary colors', () => {
+    const { rerender } = render(<Arrow primary />)
+    expect(document.querySelector(`g[stroke="${ThemePalette.primary}"]`)).toBeTruthy()
+    rerender(<Arrow />)
+    expect(document.querySelector(`g[stroke="${ThemePalette.grayscale[4]}"]`)).toBeTruthy()
+  })
+})

+ 36 - 0
src/components/ui/AutocompleteInput/AutocompleteInput.spec.tsx

@@ -0,0 +1,36 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import AutocompleteInput from './AutocompleteInput'
+
+describe('AutocompleteInput', () => {
+  it('renders correct data', () => {
+    render(<AutocompleteInput value="searching" onChange={() => { }} />)
+    expect(TestUtils.selectInput('TextInput__Input')!.value).toBe('searching')
+  })
+
+  it('calls focus and blur', () => {
+    const onFocus = jest.fn()
+    const onBlur = jest.fn()
+    render(<AutocompleteInput value="" onChange={() => { }} onFocus={onFocus} onBlur={onBlur} />)
+    const inputElement = TestUtils.select('TextInput__Input')
+    inputElement?.focus()
+    expect(onFocus).toHaveBeenCalled()
+    inputElement?.blur()
+    expect(onBlur).toHaveBeenCalled()
+  })
+})

+ 0 - 2
src/components/ui/AutocompleteInput/AutocompleteInput.tsx

@@ -111,7 +111,6 @@ class AutocompleteInput extends React.Component<Props, State> {
         }}
         }}
       >
       >
         <TextInput
         <TextInput
-          data-test-id="acInput-text"
           disabled={disabled}
           disabled={disabled}
           value={this.props.value}
           value={this.props.value}
           onChange={e => { this.props.onChange(e.target.value) }}
           onChange={e => { this.props.onChange(e.target.value) }}
@@ -134,7 +133,6 @@ class AutocompleteInput extends React.Component<Props, State> {
           onInputKeyDown={this.props.onInputKeyDown}
           onInputKeyDown={this.props.onInputKeyDown}
         />
         />
         <Arrow
         <Arrow
-          data-test-id="acInput-arrow"
           disabled={disabled}
           disabled={disabled}
           dangerouslySetInnerHTML={{ __html: arrowImage }}
           dangerouslySetInnerHTML={{ __html: arrowImage }}
           onClick={() => { if (this.textInputRef) this.textInputRef.focus() }}
           onClick={() => { if (this.textInputRef) this.textInputRef.focus() }}

+ 37 - 0
src/components/ui/Button/Button.spec.tsx

@@ -0,0 +1,37 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import { ThemePalette } from '@src/components/Theme'
+import Button from './Button'
+
+describe('Button', () => {
+  it('should render with different style props', () => {
+    const { rerender } = render(<Button disabled />)
+    expect(document.querySelector('button')?.hasAttribute('disabled')).toBeTruthy()
+    expect(TestUtils.rgbToHex(window.getComputedStyle(document.querySelector('button')!).backgroundColor)).toBe(ThemePalette.primary)
+
+    rerender(<Button secondary />)
+    expect(TestUtils.rgbToHex(window.getComputedStyle(document.querySelector('button')!).backgroundColor)).toBe(ThemePalette.secondaryLight)
+  })
+
+  it('fires click', () => {
+    const onClick = jest.fn()
+    render(<Button onClick={onClick} />)
+    document.querySelector('button')?.click()
+    expect(onClick).toHaveBeenCalled()
+  })
+})

+ 0 - 43
src/components/ui/Button/test.tsx

@@ -1,43 +0,0 @@
-/*
-Copyright (C) 2017  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { shallow } from 'enzyme'
-import sinon from 'sinon'
-import Button from '.'
-
-const wrap = props => shallow(<Button {...props} />)
-
-describe('Button Component', () => {
-  it('renders with different combination of props', () => {
-    let wrapper = wrap({ disabled: true })
-    expect(wrapper.prop('disabled')).toBe(true)
-    wrapper = wrap({ primary: true })
-    expect(wrapper.prop('disabled')).toBe(undefined)
-    expect(wrapper.prop('primary')).toBe(true)
-    wrapper = wrap({ disabled: true, primary: true })
-    expect(wrapper.prop('disabled')).toBe(true)
-    expect(wrapper.prop('primary')).toBe(true)
-  })
-
-  it('dispatches click event', () => {
-    const onButtonClick = sinon.spy()
-    const wrapper = wrap({ onClick: onButtonClick })
-    wrapper.simulate('click')
-    expect(onButtonClick.calledOnce).toBe(true)
-  })
-})
-
-
-

+ 39 - 0
src/components/ui/Checkbox/Checkbox.spec.tsx

@@ -0,0 +1,39 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import userEvent from '@testing-library/user-event'
+
+import TestUtils from '@tests/TestUtils'
+import Checkbox from './Checkbox'
+
+describe('Checkbox', () => {
+  it('dispatches change on space key', () => {
+    const onChange = jest.fn()
+    const { rerender } = render(<Checkbox onChange={onChange} />)
+    userEvent.type(TestUtils.select('Checkbox__Wrapper')!, ' ')
+    expect(onChange).toHaveBeenCalledWith(true)
+    rerender(<Checkbox onChange={onChange} checked />)
+    userEvent.type(TestUtils.select('Checkbox__Wrapper')!, ' ')
+    expect(onChange).toHaveBeenCalledWith(false)
+  })
+
+  it('doesn\'t dispatch change if disabled', () => {
+    const onChange = jest.fn()
+    render(<Checkbox onChange={onChange} disabled />)
+    userEvent.type(TestUtils.select('Checkbox__Wrapper')!, ' ')
+    expect(onChange).not.toHaveBeenCalled()
+  })
+})

+ 0 - 2
src/components/ui/Checkbox/Checkbox.tsx

@@ -56,7 +56,6 @@ type Props = {
   checked?: boolean,
   checked?: boolean,
   disabled?: boolean,
   disabled?: boolean,
   onChange?: (checked: boolean) => void,
   onChange?: (checked: boolean) => void,
-  'data-test-id'?: string,
   onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void,
   onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void,
   onMouseUp?: (e: React.MouseEvent<HTMLDivElement>) => void,
   onMouseUp?: (e: React.MouseEvent<HTMLDivElement>) => void,
 }
 }
@@ -81,7 +80,6 @@ class Checkbox extends React.Component<Props> {
   render() {
   render() {
     return (
     return (
       <Wrapper
       <Wrapper
-        data-test-id={this.props['data-test-id'] || 'checkbox'}
         className={this.props.className}
         className={this.props.className}
         onClick={() => { this.handleClick() }}
         onClick={() => { this.handleClick() }}
         checked={this.props.checked}
         checked={this.props.checked}

+ 0 - 44
src/components/ui/Checkbox/test.tsx

@@ -1,44 +0,0 @@
-/*
-Copyright (C) 2017  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { shallow } from 'enzyme'
-import sinon from 'sinon'
-import Checkbox from '../Checkbox'
-
-const wrap = props => shallow(<Checkbox {...props} />)
-
-describe('Checkbox Component', () => {
-  it('passes `checked` to the component', () => {
-    let wrapper = wrap({ checked: true, onChange: () => {} })
-    expect(wrapper.prop('checked')).toBe(true)
-  })
-
-  it('calls `onChange` with correct value, on click', () => {
-    let onChange = sinon.spy()
-    let wrapper = wrap({ checked: false, onChange })
-    wrapper.simulate('click')
-    expect(onChange.args[0][0]).toBe(true)
-  })
-
-  it('doesn\'t call `onChange` if disabled', () => {
-    let onChange = sinon.spy()
-    let wrapper = wrap({ checked: false, onChange, disabled: true })
-    wrapper.simulate('click')
-    expect(onChange.notCalled).toBe(true)
-  })
-})
-
-
-

+ 14 - 15
src/components/ui/StatusComponents/StatusPill/test.tsx → src/components/ui/CopyButton/CopyButton.spec.tsx

@@ -1,5 +1,5 @@
 /*
 /*
-Copyright (C) 2017  Cloudbase Solutions SRL
+Copyright (C) 2021  Cloudbase Solutions SRL
 This program is free software: you can redistribute it and/or modify
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 published by the Free Software Foundation, either version 3 of the
@@ -13,22 +13,21 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
 import React from 'react'
 import React from 'react'
-import { shallow } from 'enzyme'
-import StatusPill from '.'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import CopyButton from './CopyButton'
 
 
-const wrap = props => shallow(<StatusPill {...props} />)
-
-describe('StatusPill Component', () => {
-  it('renders label if given', () => {
-    let wrapper = wrap({ label: 'the_value', status: 'COMPLETED' })
-    expect(wrapper.dive().text()).toBe('the_value')
+describe('CopyButton', () => {
+  it('renders with no opacity', () => {
+    render(<CopyButton />)
+    expect(window.getComputedStyle(TestUtils.select('CopyButton__Wrapper')!).opacity).toBe('0')
   })
   })
 
 
-  it('renders status as label if no label is given', () => {
-    let wrapper = wrap({ status: 'COMPLETED' })
-    expect(wrapper.dive().text()).toBe('COMPLETED')
+  it('dispatches click', () => {
+    const onClick = jest.fn()
+    render(<CopyButton onClick={onClick} />)
+    const button = TestUtils.select('CopyButton__Wrapper') as HTMLElement
+    button.click()
+    expect(onClick).toHaveBeenCalled()
   })
   })
 })
 })
-
-
-

+ 38 - 0
src/components/ui/CopyMultilineValue/CopyMultilineValue.spec.tsx

@@ -0,0 +1,38 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import DomUtils from '@src/utils/DomUtils'
+import CopyMultineValue from './CopyMultilineValue'
+
+jest.mock('../../../utils/DomUtils')
+
+describe('CopyMultilineValue', () => {
+  it('copies value to clipboard', () => {
+    const onCopy = jest.fn()
+    render(<CopyMultineValue value="test value" onCopy={onCopy} />)
+    TestUtils.select('CopyMultilineValue__Wrapper')!.click()
+    expect(DomUtils.copyTextToClipboard).toHaveBeenCalledWith('test value')
+    expect(onCopy).toHaveBeenCalledWith('test value')
+  })
+
+  it('transforms dangerous HTML', () => {
+    const onCopy = jest.fn()
+    render(<CopyMultineValue useDangerousHtml onCopy={onCopy} value="this<br />is <b>OK</b>" />)
+    TestUtils.select('CopyMultilineValue__Wrapper')!.click()
+    expect(onCopy).toHaveBeenCalledWith('this\nis OK')
+  })
+})

+ 0 - 2
src/components/ui/CopyMultilineValue/CopyMultilineValue.tsx

@@ -34,7 +34,6 @@ const Wrapper = styled.div<any>`
 `
 `
 
 
 type Props = {
 type Props = {
-  'data-test-id'?: string,
   value: string | null | undefined,
   value: string | null | undefined,
   onCopy?: (value: string) => void,
   onCopy?: (value: string) => void,
   useDangerousHtml?: boolean,
   useDangerousHtml?: boolean,
@@ -67,7 +66,6 @@ class CopyMultineValue extends React.Component<Props> {
     return (
     return (
       <Wrapper
       <Wrapper
         onClick={() => { this.handleCopy() }}
         onClick={() => { this.handleCopy() }}
-        data-test-id={(this.props && this.props['data-test-id']) || 'copyMultilineValue'}
       >
       >
         {text}
         {text}
         <CopyButtonStyled />
         <CopyButtonStyled />

+ 0 - 38
src/components/ui/CopyMultilineValue/test.tsx

@@ -1,38 +0,0 @@
-/*
-Copyright (C) 2018  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { shallow } from 'enzyme'
-import sinon from 'sinon'
-import CopyMultilineValue from '../CopyMultilineValue'
-
-const wrap = props => shallow(<CopyMultilineValue value="" {...props} />)
-
-describe('CopyMultilineValue Component', () => {
-  it('renders `value`', () => {
-    const wrapper = wrap({ value: 'the_value' })
-    expect(wrapper.dive().text()).toBe('the_value<Styled(CopyButton) />')
-  })
-
-  it('copies `value` to clipboard', () => {
-    const onCopy = sinon.spy()
-    const wrapper = wrap({ value: 'the_value', onCopy })
-    wrapper.simulate('click')
-    expect(onCopy.calledOnce).toBe(true)
-    expect(onCopy.args[0][0]).toBe('the_value')
-  })
-})
-
-
-

+ 34 - 0
src/components/ui/CopyValue/CopyValue.spec.tsx

@@ -0,0 +1,34 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import DomUtils from '@src/utils/DomUtils'
+import CopyValue from './CopyValue'
+
+jest.mock('../../../utils/DomUtils')
+
+describe('CopyValue', () => {
+  it('copies value to clipboard', () => {
+    render(<CopyValue value="value" />)
+    TestUtils.select('CopyValue__Wrapper')!.click()
+    expect(DomUtils.copyTextToClipboard).toHaveBeenCalledWith('value')
+  })
+
+  it('capitalizes the value', () => {
+    render(<CopyValue capitalize value="value" />)
+    expect(window.getComputedStyle(TestUtils.select('CopyValue__Wrapper')!).textTransform).toBe('capitalize')
+  })
+})

+ 0 - 3
src/components/ui/CopyValue/CopyValue.tsx

@@ -46,7 +46,6 @@ type Props = {
   width?: string,
   width?: string,
   maxWidth?: string,
   maxWidth?: string,
   capitalize?: boolean,
   capitalize?: boolean,
-  'data-test-id'?: string,
   onCopy?: (value: string) => void,
   onCopy?: (value: string) => void,
   style?: React.CSSProperties
   style?: React.CSSProperties
 }
 }
@@ -71,12 +70,10 @@ class CopyValue extends React.Component<Props> {
         onClick={(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => { this.handleCopyIdClick(e) }}
         onClick={(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => { this.handleCopyIdClick(e) }}
         onMouseDown={(e: { stopPropagation: () => void }) => { e.stopPropagation() }}
         onMouseDown={(e: { stopPropagation: () => void }) => { e.stopPropagation() }}
         onMouseUp={(e: { stopPropagation: () => void }) => { e.stopPropagation() }}
         onMouseUp={(e: { stopPropagation: () => void }) => { e.stopPropagation() }}
-        data-test-id={this.props['data-test-id'] || 'copyValue'}
         capitalize={this.props.capitalize}
         capitalize={this.props.capitalize}
         style={this.props.style}
         style={this.props.style}
       >
       >
         <Value
         <Value
-          data-test-id="copyValue-value"
           width={this.props.width}
           width={this.props.width}
           maxWidth={this.props.maxWidth}
           maxWidth={this.props.maxWidth}
         >{this.props.label || this.props.value}
         >{this.props.label || this.props.value}

+ 0 - 39
src/components/ui/CopyValue/test.tsx

@@ -1,39 +0,0 @@
-/*
-Copyright (C) 2018  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { shallow } from 'enzyme'
-import sinon from 'sinon'
-import TestWrapper from '../../../utils/TestWrapper'
-import CopyValue from '../CopyValue'
-
-const wrap = props => new TestWrapper(shallow(<CopyValue value="the_value" {...props} />), 'copyValue')
-
-describe('CopyValue Component', () => {
-  it('renders `value`', () => {
-    const wrapper = wrap()
-    expect(wrapper.findText('value')).toBe('the_value')
-  })
-
-  it('copies `value` to clipboard', () => {
-    const onCopy = sinon.spy()
-    const wrapper = wrap({ onCopy })
-    wrapper.simulate('click')
-    expect(onCopy.calledOnce).toBe(true)
-    expect(onCopy.args[0][0]).toBe('the_value')
-  })
-})
-
-
-

+ 61 - 0
src/components/ui/DatetimePicker/DatetimePicker.spec.tsx

@@ -0,0 +1,61 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import moment from 'moment'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import DatetimePicker from './DatetimePicker'
+
+const DATE = new Date('2021-11-12T12:32:44.426Z')
+
+describe('DatetimePicker', () => {
+  it('renders date value in UTC timezone in dropdown label', () => {
+    render(
+      <DatetimePicker
+        onChange={() => { }}
+        timezone="utc"
+        value={DATE}
+      />,
+    )
+
+    const expected = moment(DATE)
+      .add(new Date().getTimezoneOffset(), 'minutes')
+      .format('DD/MM/YYYY hh:mm A')
+
+    expect(TestUtils.select('DropdownButton__Label')?.innerHTML).toEqual(expected)
+  })
+
+  it('changes the date', () => {
+    render(
+      <DatetimePicker
+        onChange={() => { }}
+        timezone="utc"
+        value={DATE}
+      />,
+    )
+    expect(TestUtils.select('DatetimePicker__Portal')).toBeNull()
+    TestUtils.select('DropdownButton__Wrapper')?.click()
+    expect(TestUtils.select('DatetimePicker__Portal')).not.toBeNull()
+    const firstDay = document.querySelector<HTMLElement>('td.rdtDay[data-value="1"]')
+    firstDay?.click()
+
+    const expected = moment(DATE)
+      .set('date', 1)
+      .add(new Date().getTimezoneOffset(), 'minutes')
+      .format('DD/MM/YYYY hh:mm A')
+
+    expect(TestUtils.select('DropdownButton__Label')?.innerHTML).toEqual(expected)
+  })
+})

+ 0 - 1
src/components/ui/DatetimePicker/DatetimePicker.tsx

@@ -224,7 +224,6 @@ class DatetimePicker extends React.Component<Props, State> {
         <Wrapper>
         <Wrapper>
           <DropdownButtonStyled
           <DropdownButtonStyled
             customRef={e => { this.buttonRef = e }}
             customRef={e => { this.buttonRef = e }}
-            data-test-id="datetimePicker-dropdownButton"
             width={207}
             width={207}
             value={(timezoneDate && moment(timezoneDate).format('DD/MM/YYYY hh:mm A')) || '-'}
             value={(timezoneDate && moment(timezoneDate).format('DD/MM/YYYY hh:mm A')) || '-'}
             centered
             centered

+ 0 - 42
src/components/ui/DatetimePicker/test.tsx

@@ -1,42 +0,0 @@
-/*
-Copyright (C) 2017  Cloudbase Solutions SRL
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-import React from 'react'
-import { shallow } from 'enzyme'
-import moment from 'moment'
-import sinon from 'sinon'
-import TestWrapper from '../../../utils/TestWrapper'
-import DatetimePicker from '.'
-
-const wrap = props => new TestWrapper(shallow(<DatetimePicker timezone="local" {...props} />), 'datetimePicker')
-
-describe('DateTimePicker Component', () => {
-  it('renders date value in dropdown label', () => {
-    let onChange = sinon.spy()
-    let wrapper = wrap({ value: new Date(2017, 3, 21, 14, 22), onChange })
-    let label = '21/04/2017 02:22 PM'
-    expect(wrapper.find('dropdownButton').prop('value')).toBe(label)
-  })
-
-  it('renders date value in UTC timezone in dropdown label', () => {
-    let onChange = sinon.spy()
-    const date = new Date(2017, 3, 21, 14, 22)
-    let wrapper = wrap({ value: date, onChange, timezone: 'utc' })
-    const label = moment(date).add(new Date().getTimezoneOffset(), 'minutes').format('DD/MM/YYYY hh:mm A')
-    expect(wrapper.find('dropdownButton').prop('value')).toBe(label)
-  })
-})
-
-
-

+ 94 - 0
src/components/ui/Dropdowns/ActionDropdown/ActionDropdown.spec.tsx

@@ -0,0 +1,94 @@
+/*
+Copyright (C) 2021  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import React from 'react'
+import { render } from '@testing-library/react'
+import TestUtils from '@tests/TestUtils'
+import ActionDropdown, { Action } from './ActionDropdown'
+
+const ACTIONS: Action[] = [
+  {
+    label: 'Action 1',
+    title: 'Action 1 Description',
+    action: jest.fn(),
+  },
+  {
+    label: 'Action 2',
+    disabled: true,
+    action: jest.fn(),
+
+  },
+  {
+    label: 'Action 3',
+    loading: true,
+    action: jest.fn(),
+  },
+  {
+    label: 'Action 4',
+    hidden: true,
+    action: jest.fn(),
+  },
+]
+
+describe('ActionDropdown', () => {
+  it('renders button label', () => {
+    const { rerender } = render(<ActionDropdown actions={ACTIONS} />)
+    expect(TestUtils.select('DropdownButton__Label')?.textContent).toBe('Actions')
+    rerender(<ActionDropdown actions={ACTIONS} label="Actions Label" />)
+    expect(TestUtils.select('DropdownButton__Label')?.textContent).toBe('Actions Label')
+  })
+
+  it('renders only visible actions', () => {
+    render(<ActionDropdown actions={ACTIONS} />)
+    TestUtils.select('DropdownButton__Wrapper')!.click()
+    expect(TestUtils.selectAll('ActionDropdown__ListItem').length).toBe(3)
+    TestUtils.selectAll('ActionDropdown__ListItem').forEach((item, index) => {
+      expect(item.textContent).toBe(ACTIONS[index].label)
+    })
+  })
+
+  it('renders actions with props', () => {
+    render(<ActionDropdown actions={ACTIONS} />)
+    TestUtils.select('DropdownButton__Wrapper')!.click()
+    TestUtils.selectAll('ActionDropdown__ListItem').forEach((item, index) => {
+      if (ACTIONS[index].disabled) {
+        expect(item.hasAttribute('disabled')).toBe(true)
+      } else {
+        expect(item.hasAttribute('disabled')).toBe(false)
+      }
+      if (ACTIONS[index].title) {
+        expect(item.getAttribute('title')).toBe(ACTIONS[index].title)
+      }
+      if (ACTIONS[index].loading) {
+        expect(TestUtils.select('StatusIcon__Wrapper', item)).toBeTruthy()
+      } else {
+        expect(TestUtils.select('StatusIcon__Wrapper', item)).toBeFalsy()
+      }
+    })
+  })
+
+  it('fires click events correctly', () => {
+    render(<ActionDropdown actions={ACTIONS} />)
+    TestUtils.select('DropdownButton__Wrapper')!.click()
+    TestUtils.selectAll('ActionDropdown__ListItem').forEach((item, index) => {
+      item.click()
+      if (ACTIONS[index].disabled || ACTIONS[index].loading) {
+        expect(ACTIONS[index].action).not.toHaveBeenCalled()
+      } else {
+        TestUtils.select('DropdownButton__Wrapper')!.click()
+        expect(ACTIONS[index].action).toHaveBeenCalled()
+      }
+    })
+  })
+})

+ 1 - 4
src/components/ui/Dropdowns/ActionDropdown/ActionDropdown.tsx

@@ -66,7 +66,6 @@ export type Props = {
   label: string,
   label: string,
   actions: Action[],
   actions: Action[],
   style?: any,
   style?: any,
-  'data-test-id'?: string,
   largeItems?: boolean
   largeItems?: boolean
 }
 }
 
 
@@ -172,7 +171,6 @@ class ActionDropdown extends React.Component<Props, State> {
             onClick={() => { this.handleItemClick(action) }}
             onClick={() => { this.handleItemClick(action) }}
             color={action.color}
             color={action.color}
             disabled={action.disabled}
             disabled={action.disabled}
-            data-test-id={`${TEST_ID}-listItem-${action.label}`}
             title={action.title}
             title={action.title}
             large={this.props.largeItems}
             large={this.props.largeItems}
           >
           >
@@ -206,14 +204,13 @@ class ActionDropdown extends React.Component<Props, State> {
 
 
   render() {
   render() {
     return (
     return (
-      <Wrapper style={this.props.style} data-test-id={this.props['data-test-id']}>
+      <Wrapper style={this.props.style}>
         <DropdownButton
         <DropdownButton
           secondary
           secondary
           centered
           centered
           value={this.props.label}
           value={this.props.label}
           customRef={ref => { this.buttonRef = ref }}
           customRef={ref => { this.buttonRef = ref }}
           onClick={() => { this.handleButtonClick() }}
           onClick={() => { this.handleButtonClick() }}
-          data-test-id={`${TEST_ID}-dropdownButton`}
         />
         />
         {this.renderList()}
         {this.renderList()}
       </Wrapper>
       </Wrapper>

Некоторые файлы не были показаны из-за большого количества измененных файлов