foreman_rh_cloud 3.0.18.1 → 3.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_inventory_upload/tasks_controller.rb +14 -3
  3. data/app/controllers/foreman_inventory_upload/uploads_settings_controller.rb +8 -0
  4. data/app/models/insights_resolution.rb +1 -1
  5. data/config/routes.rb +1 -1
  6. data/lib/foreman_inventory_upload.rb +5 -0
  7. data/lib/foreman_inventory_upload/generators/queries.rb +1 -1
  8. data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +5 -1
  9. data/lib/foreman_rh_cloud/version.rb +1 -1
  10. data/lib/insights_cloud/async/insights_full_sync.rb +17 -21
  11. data/lib/inventory_sync/async/host_result.rb +11 -6
  12. data/lib/inventory_sync/async/inventory_full_sync.rb +24 -41
  13. data/lib/inventory_sync/async/inventory_hosts_sync.rb +34 -0
  14. data/lib/inventory_sync/async/query_inventory_job.rb +54 -0
  15. data/lib/tasks/insights.rake +1 -1
  16. data/package.json +1 -1
  17. data/test/jobs/insights_full_sync_test.rb +14 -10
  18. data/test/jobs/inventory_full_sync_test.rb +181 -11
  19. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +1 -1
  20. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +0 -1
  21. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonActions.js +81 -46
  22. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonConstants.js +3 -3
  23. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonSelectors.js +6 -12
  24. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonFixtures.js +1 -9
  25. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonSelectors.test.js +18 -27
  26. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonSelectors.test.js.snap +1 -16
  27. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/integrations.test.js.snap +58 -0
  28. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/integrations.test.js +51 -0
  29. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/index.js +2 -5
  30. data/webpack/ForemanInventoryUpload/ForemanInventoryUploadReducers.js +0 -2
  31. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +2 -0
  32. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +4 -0
  33. metadata +25 -25
  34. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonReducer.js +0 -36
  35. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonActions.test.js +0 -31
  36. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonReducer.test.js +0 -26
  37. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonActions.test.js.snap +0 -98
  38. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonReducer.test.js.snap +0 -18
@@ -2,13 +2,25 @@ require 'test_plugin_helper'
2
2
 
3
3
  class InventoryFullSyncTest < ActiveJob::TestCase
4
4
  setup do
5
- @host1 = FactoryBot.create(:host, :managed, name: 'host1')
6
-
7
5
  User.current = User.find_by(login: 'secret_admin')
8
6
 
9
7
  env = FactoryBot.create(:katello_k_t_environment)
10
8
  cv = env.content_views << FactoryBot.create(:katello_content_view, organization: env.organization)
11
9
 
10
+ # this host would pass our plugin queries, so it could be uploaded to the cloud.
11
+ @host1 = FactoryBot.create(
12
+ :host,
13
+ :with_subscription,
14
+ :with_content,
15
+ content_view: cv.first,
16
+ lifecycle_environment: env,
17
+ organization: env.organization
18
+ )
19
+
20
+ pool = FactoryBot.create(:katello_pool, account_number: '1234', cp_id: 1)
21
+
22
+ @host1.subscription_facet.pools << pool
23
+
12
24
  # this host would pass our plugin queries, so it could be uploaded to the cloud.
13
25
  @host2 = FactoryBot.create(
14
26
  :host,
@@ -19,7 +31,8 @@ class InventoryFullSyncTest < ActiveJob::TestCase
19
31
  organization: env.organization
20
32
  )
21
33
 
22
- @host2.subscription_facet.pools << FactoryBot.create(:katello_pool, account_number: '1234', cp_id: 1)
34
+ @host2.subscription_facet.pools << pool
35
+ @host2_inventory_id = '4536bf5c-ff03-4154-a8c9-32ff4b40e40c'
23
36
 
24
37
  ForemanInventoryUpload::Generators::Queries.instance_variable_set(:@fact_names, nil)
25
38
 
@@ -28,8 +41,165 @@ class InventoryFullSyncTest < ActiveJob::TestCase
28
41
  "total": 3,
29
42
  "count": 3,
30
43
  "page": 1,
31
- "per_page": 50,
32
- "results": [{"fqdn": "#{@host1.fqdn}"}]
44
+ "per_page": 3,
45
+ "results": [
46
+ {
47
+ "insights_id": "72d29d75-dbbf-4121-9566-2f581ab77f36",
48
+ "rhel_machine_id": null,
49
+ "subscription_manager_id": "#{@host2.subscription_facet.uuid}",
50
+ "satellite_id": "bb72bf95-0a19-4090-8009-f0d8c68aca61",
51
+ "bios_uuid": "b48a7e5f-cb50-4029-a75e-366bf43db641",
52
+ "ip_addresses": [
53
+ "192.168.122.56"
54
+ ],
55
+ "fqdn": "#{@host2.fqdn}",
56
+ "mac_addresses": [
57
+ "52:54:00:aa:12:12",
58
+ "00:00:00:00:00:00"
59
+ ],
60
+ "external_id": null,
61
+ "id": "#{@host2_inventory_id}",
62
+ "account": "1460290",
63
+ "display_name": "insights-rh7.example.com",
64
+ "ansible_host": null,
65
+ "facts": [
66
+ {
67
+ "namespace": "satellite",
68
+ "facts": {
69
+ "virtual_host_name": "virt-who-nobody.home-1",
70
+ "satellite_instance_id": "fc4d0cb0-a0b0-421e-b096-b028319b8e47",
71
+ "is_simple_content_access": false,
72
+ "distribution_version": "7.3",
73
+ "satellite_version": "6.8.4",
74
+ "organization_id": 1,
75
+ "is_hostname_obfuscated": false,
76
+ "virtual_host_uuid": "a90e6294-4766-420a-8dc0-3ec5b96d60ec"
77
+ }
78
+ },
79
+ {
80
+ "namespace": "yupana",
81
+ "facts": {
82
+ "report_platform_id": "d37afa50-08ce-4efb-a0e5-759c2a016661",
83
+ "report_slice_id": "5bf791d7-5e30-4a3c-929a-11dd9fa6eb72",
84
+ "source": "Satellite",
85
+ "yupana_host_id": "e85958b6-58db-4cfd-aeb6-01ee81bc0f43",
86
+ "account": "1460290"
87
+ }
88
+ }
89
+ ],
90
+ "reporter": "puptoo",
91
+ "stale_timestamp": "2021-03-19T07:57:42.466399+00:00",
92
+ "stale_warning_timestamp": "2021-03-26T07:57:42.466399+00:00",
93
+ "culled_timestamp": "2021-04-02T07:57:42.466399+00:00",
94
+ "created": "2021-02-08T14:36:03.613880+00:00",
95
+ "updated": "2021-03-18T02:57:42.535250+00:00"
96
+ },
97
+ {
98
+ "insights_id": "e0dc5144-d78e-43ed-97be-a7a21d1b6946",
99
+ "rhel_machine_id": null,
100
+ "subscription_manager_id": "0f97ee19-6862-4900-aea4-f121c8754776",
101
+ "satellite_id": "0f97ee19-6862-4900-aea4-f121c8754776",
102
+ "bios_uuid": "6a0b199a-8225-4ade-ae44-3b18cfc84a01",
103
+ "ip_addresses": [
104
+ "192.168.122.136"
105
+ ],
106
+ "fqdn": "#{@host1.fqdn}",
107
+ "mac_addresses": [
108
+ "52:54:00:02:d1:2a",
109
+ "00:00:00:00:00:00"
110
+ ],
111
+ "external_id": null,
112
+ "id": "3255d080-e6c1-44e2-8d72-b044b9a38d8f",
113
+ "account": "1460290",
114
+ "display_name": "insights-rh8.example.com",
115
+ "ansible_host": null,
116
+ "facts": [
117
+ {
118
+ "namespace": "satellite",
119
+ "facts": {
120
+ "virtual_host_name": "virt-who-nobody.home-1",
121
+ "satellite_instance_id": "fc4d0cb0-a0b0-421e-b096-b028319b8e47",
122
+ "is_simple_content_access": false,
123
+ "distribution_version": "8.3",
124
+ "satellite_version": "6.8.4",
125
+ "organization_id": 1,
126
+ "is_hostname_obfuscated": false,
127
+ "virtual_host_uuid": "a90e6294-4766-420a-8dc0-3ec5b96d60ec"
128
+ }
129
+ },
130
+ {
131
+ "namespace": "yupana",
132
+ "facts": {
133
+ "report_platform_id": "d37afa50-08ce-4efb-a0e5-759c2a016661",
134
+ "report_slice_id": "5bf791d7-5e30-4a3c-929a-11dd9fa6eb72",
135
+ "source": "Satellite",
136
+ "yupana_host_id": "78c62486-0ac4-406c-a4c0-3a1f81112a2d",
137
+ "account": "1460290"
138
+ }
139
+ }
140
+ ],
141
+ "reporter": "puptoo",
142
+ "stale_timestamp": "2021-03-19T06:05:12.092136+00:00",
143
+ "stale_warning_timestamp": "2021-03-26T06:05:12.092136+00:00",
144
+ "culled_timestamp": "2021-04-02T06:05:12.092136+00:00",
145
+ "created": "2021-02-08T13:22:50.555671+00:00",
146
+ "updated": "2021-03-18T01:05:12.131847+00:00"
147
+ },
148
+ {
149
+ "insights_id": "b533848e-465f-4f1a-9b2b-b71cb2d5239d",
150
+ "rhel_machine_id": null,
151
+ "subscription_manager_id": "d29bde40-348e-437c-8acf-8fa98320fc1b",
152
+ "satellite_id": "d29bde40-348e-437c-8acf-8fa98320fc1b",
153
+ "bios_uuid": "3cd5d972-cfb5-451a-8314-fd2f56629d7c",
154
+ "ip_addresses": [
155
+ "172.16.5.39",
156
+ "fd6e:2298:736e::857",
157
+ "fd6e:2298:736e:0:2c66:6101:9cc6:2b23"
158
+ ],
159
+ "fqdn": "rhel8-demo.oss-lab.net",
160
+ "mac_addresses": [
161
+ "6e:66:a6:fe:fc:07",
162
+ "00:00:00:00:00:00"
163
+ ],
164
+ "external_id": null,
165
+ "id": "59ab38db-c25b-4fc7-bfb2-c8eb01d865a9",
166
+ "account": "1460290",
167
+ "display_name": "rhel8-demo.oss-lab.net",
168
+ "ansible_host": null,
169
+ "facts": [
170
+ {
171
+ "namespace": "satellite",
172
+ "facts": {
173
+ "satellite_instance_id": "fb3643d8-9030-487b-b95c-684783806ffd",
174
+ "system_purpose_sla": "",
175
+ "is_simple_content_access": false,
176
+ "distribution_version": "8.3",
177
+ "satellite_version": "6.8.1",
178
+ "organization_id": 1,
179
+ "system_purpose_role": "",
180
+ "system_purpose_usage": "",
181
+ "is_hostname_obfuscated": false
182
+ }
183
+ },
184
+ {
185
+ "namespace": "yupana",
186
+ "facts": {
187
+ "report_platform_id": "fa8b924c-51ee-479d-97d2-b4623cf1d4aa",
188
+ "report_slice_id": "0b49103f-6471-4ade-ad74-a51537bc5691",
189
+ "source": "Satellite",
190
+ "yupana_host_id": "30e43340-12fb-445d-b23f-faaf5cbc2092",
191
+ "account": "1460290"
192
+ }
193
+ }
194
+ ],
195
+ "reporter": "puptoo",
196
+ "stale_timestamp": "2021-03-19T05:55:23.700781+00:00",
197
+ "stale_warning_timestamp": "2021-03-26T05:55:23.700781+00:00",
198
+ "culled_timestamp": "2021-04-02T05:55:23.700781+00:00",
199
+ "created": "2021-01-13T20:05:51.059012+00:00",
200
+ "updated": "2021-03-18T00:55:23.739162+00:00"
201
+ }
202
+ ]
33
203
  }
34
204
  INVENTORY_JSON
35
205
  @inventory = JSON.parse(inventory_json)
@@ -71,21 +241,21 @@ class InventoryFullSyncTest < ActiveJob::TestCase
71
241
  test 'Host status should be SYNC for inventory hosts' do
72
242
  InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(@inventory)
73
243
 
74
- InventorySync::Async::InventoryFullSync.perform_now(@host1.organization)
244
+ ForemanTasks.sync_task(InventorySync::Async::InventoryFullSync, @host2.organization)
75
245
 
76
- @host1.reload
246
+ @host2.reload
77
247
 
78
- assert_equal InventorySync::InventoryStatus::SYNC, InventorySync::InventoryStatus.where(host_id: @host1.id).first.status
248
+ assert_equal InventorySync::InventoryStatus::SYNC, InventorySync::InventoryStatus.where(host_id: @host2.id).first.status
249
+ assert_equal @host2_inventory_id, @host2.insights.uuid
79
250
  end
80
251
 
81
252
  test 'Host status should be DISCONNECT for hosts that are not returned from cloud' do
82
253
  InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(@inventory)
83
254
  FactoryBot.create(:fact_value, fact_name: fact_names['virt::uuid'], value: '1234', host: @host2)
84
255
 
85
- InventorySync::Async::InventoryFullSync.perform_now(@host2.organization)
86
-
256
+ ForemanTasks.sync_task(InventorySync::Async::InventoryFullSync, @host1.organization)
87
257
  @host2.reload
88
258
 
89
- assert_equal InventorySync::InventoryStatus::DISCONNECT, InventorySync::InventoryStatus.where(host_id: @host2.id).first.status
259
+ assert_equal InventorySync::InventoryStatus::DISCONNECT, InventorySync::InventoryStatus.where(host_id: @host1.id).first.status
90
260
  end
91
261
  end
@@ -18,7 +18,7 @@ const InventoryFilter = ({
18
18
  const initialTerm =
19
19
  organization === __(ANY_ORGANIZATION) ? '' : organization;
20
20
  handleFilterChange(initialTerm);
21
- }, [organization]);
21
+ }, []);
22
22
 
23
23
  return (
24
24
  <form id="inventory_filter_form">
@@ -37,7 +37,6 @@ Object {
37
37
  "inventoryFilter": Object {
38
38
  "filterTerm": "some-org",
39
39
  },
40
- "inventorySync": Object {},
41
40
  },
42
41
  },
43
42
  },
@@ -1,57 +1,92 @@
1
1
  import React from 'react';
2
- import { API } from 'foremanReact/redux/API';
2
+ import { get, post } from 'foremanReact/redux/API';
3
+ import { withInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
3
4
  import { addToast } from 'foremanReact/redux/actions/toasts';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
4
6
  import { inventoryUrl } from '../../../../ForemanInventoryHelpers';
5
7
  import Toast from './components/Toast';
6
8
  import {
7
- INVENTORY_SYNC_REQUEST,
8
- INVENTORY_SYNC_SUCCESS,
9
- INVENTORY_SYNC_ERROR,
9
+ INVENTORY_SYNC,
10
+ INVENTORY_SYNC_TASK_UPDATE,
10
11
  } from './SyncButtonConstants';
12
+ import { foremanUrl } from '../../../../../ForemanRhCloudHelpers';
11
13
 
12
- export const handleSync = () => async dispatch => {
13
- dispatch({
14
- type: INVENTORY_SYNC_REQUEST,
15
- payload: {},
16
- });
17
- try {
18
- const {
19
- data: { syncHosts, disconnectHosts },
20
- } = await API.post(inventoryUrl('tasks'));
21
- dispatch({
22
- type: INVENTORY_SYNC_SUCCESS,
23
- payload: {
24
- syncHosts,
25
- disconnectHosts,
26
- },
27
- });
28
-
29
- dispatch(
30
- addToast({
31
- sticky: true,
32
- type: 'success',
33
- message: (
34
- <Toast syncHosts={syncHosts} disconnectHosts={disconnectHosts} />
35
- ),
36
- })
37
- );
38
- } catch ({
39
- message,
40
- response: { data: { message: toastMessage } = {} } = {},
41
- }) {
42
- dispatch({
43
- type: INVENTORY_SYNC_ERROR,
44
- payload: {
45
- error: message,
14
+ export const handleSync = () => dispatch => {
15
+ dispatch(
16
+ post({
17
+ key: INVENTORY_SYNC,
18
+ url: inventoryUrl('tasks'),
19
+ handleSuccess: ({
20
+ data: {
21
+ task: { id },
22
+ },
23
+ }) => {
24
+ dispatch(getSyncTaskInterval(id));
25
+ return dispatch(
26
+ taskPageRefererToast(id, 'info', __('Inventory sync has started:'))
27
+ );
46
28
  },
47
- });
29
+ errorToast: inventorySyncErrorToast,
30
+ })
31
+ );
32
+ };
48
33
 
49
- dispatch(
50
- addToast({
51
- sticky: true,
52
- type: 'error',
53
- message: toastMessage || message,
34
+ export const getSyncTaskInterval = id => dispatch => {
35
+ dispatch(
36
+ withInterval(
37
+ get({
38
+ key: INVENTORY_SYNC_TASK_UPDATE,
39
+ url: inventoryUrl(`tasks/${id}`),
40
+ handleSuccess: ({ data: { result, output } }, stopTaskInterval) => {
41
+ if (result === 'success') {
42
+ const {
43
+ host_statuses: { sync, disconnect },
44
+ } = output;
45
+ dispatch(
46
+ addToast({
47
+ sticky: true,
48
+ type: 'success',
49
+ message: (
50
+ <Toast syncHosts={sync} disconnectHosts={disconnect} />
51
+ ),
52
+ })
53
+ );
54
+ }
55
+ if (result === 'error') {
56
+ dispatch(
57
+ taskPageRefererToast(
58
+ id,
59
+ 'error',
60
+ __('Inventory sync has failed:'),
61
+ true
62
+ )
63
+ );
64
+ }
65
+ stopTaskInterval();
66
+ },
67
+ errorToast: inventorySyncErrorToast,
54
68
  })
55
- );
56
- }
69
+ )
70
+ );
57
71
  };
72
+
73
+ const inventorySyncErrorToast = ({ message, response }) =>
74
+ `${__('Inventory sync has failed: ')} ${response.data?.message || message}`;
75
+
76
+ const taskPageRefererToast = (taskID, toastType, prefix, sticky = false) =>
77
+ addToast({
78
+ sticky,
79
+ type: toastType,
80
+ message: (
81
+ <span>
82
+ {prefix}{' '}
83
+ <a
84
+ target="_blank"
85
+ rel="noopener noreferrer"
86
+ href={foremanUrl(`/foreman_tasks/tasks/${taskID}`)}
87
+ >
88
+ {__('view the task page for more details')}
89
+ </a>
90
+ </span>
91
+ ),
92
+ });
@@ -1,3 +1,3 @@
1
- export const INVENTORY_SYNC_REQUEST = 'INVENTORY_SYNC_REQUEST';
2
- export const INVENTORY_SYNC_SUCCESS = 'INVENTORY_SYNC_SUCCESS';
3
- export const INVENTORY_SYNC_ERROR = 'INVENTORY_SYNC_ERROR';
1
+ export const INVENTORY_SYNC = 'INVENTORY_SYNC';
2
+
3
+ export const INVENTORY_SYNC_TASK_UPDATE = 'INVENTORY_SYNC_TASK_UPDATE';
@@ -1,13 +1,7 @@
1
- import { selectForemanInventoryUpload } from '../../../../../ForemanRhCloudSelectors';
1
+ import { selectAPIResponse } from 'foremanReact/redux/API/APISelectors';
2
+ import { INVENTORY_SYNC_TASK_UPDATE } from './SyncButtonConstants';
2
3
 
3
- export const selectInventorySync = state =>
4
- selectForemanInventoryUpload(state).inventorySync;
5
-
6
- export const selectStatus = state => selectInventorySync(state).status;
7
-
8
- export const selectError = state => selectInventorySync(state).error;
9
-
10
- export const selectSyncHosts = state => selectInventorySync(state).syncHosts;
11
-
12
- export const selectDisconnectHosts = state =>
13
- selectInventorySync(state).disconnectHosts;
4
+ export const selectTaskStatus = state => {
5
+ const { result } = selectAPIResponse(state, INVENTORY_SYNC_TASK_UPDATE);
6
+ return typeof result === 'string' ? result.toUpperCase() : null;
7
+ };
@@ -1,9 +1 @@
1
- export const syncHosts = 1;
2
-
3
- export const disconnectHosts = 0;
4
-
5
- export const successResponse = { data: { syncHosts, disconnectHosts } };
6
-
7
- export const status = 'RESOLVED';
8
-
9
- export const error = 'some-error';
1
+ export const successResponse = { data: { task: { id: 1 } } };
@@ -1,35 +1,26 @@
1
1
  import { testSelectorsSnapshotWithFixtures } from '@theforeman/test';
2
- import { inventoryStateWrapper } from '../../../../../../ForemanRhCloudTestHelpers';
3
- import {
4
- status,
5
- error,
6
- syncHosts,
7
- disconnectHosts,
8
- } from './SyncButtonFixtures';
9
- import {
10
- selectInventorySync,
11
- selectStatus,
12
- selectError,
13
- selectSyncHosts,
14
- selectDisconnectHosts,
15
- } from '../SyncButtonSelectors';
2
+ import { selectTaskStatus } from '../SyncButtonSelectors';
16
3
 
17
- const state = inventoryStateWrapper({
18
- inventorySync: {
19
- status,
20
- error,
21
- syncHosts,
22
- disconnectHosts,
4
+ const state = {
5
+ API: {
6
+ INVENTORY_SYNC_TASK_UPDATE: {
7
+ response: {
8
+ endedAt: '2021-03-08T14:27:30.718+02:00',
9
+ output: {
10
+ host_statuses: {
11
+ sync: 0,
12
+ disconnect: 2,
13
+ },
14
+ },
15
+ result: 'pending',
16
+ },
17
+ status: 'RESOLVED',
18
+ },
23
19
  },
24
- });
20
+ };
25
21
 
26
22
  const fixtures = {
27
- 'should return InventorySync': () => selectInventorySync(state),
28
- 'should return InventorySync status': () => selectStatus(state),
29
- 'should return InventorySync error': () => selectError(state),
30
- 'should return InventorySync SyncHosts': () => selectSyncHosts(state),
31
- 'should return InventorySync disconnectHosts': () =>
32
- selectDisconnectHosts(state),
23
+ 'should return InventorySync status': () => selectTaskStatus(state),
33
24
  };
34
25
 
35
26
  describe('SyncButton selectors', () =>